Some checks failed
continuous-integration/drone/push Build is failing
- Complete GGZ Ecademy Laravel backend application - RESTful API for learning products, members, filters - Authentication and authorization system - Database migrations and seeders - Custom CRUD generator commands - Email notification system - Integration with frontend applications
341 lines
12 KiB
PHP
341 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Illuminate\Support\Arr;
|
|
use App\Services\LearningProductService;
|
|
use App\Repositories\FilterItemsAssociation;
|
|
use App\Http\Resources\LearningProductResource;
|
|
use App\Http\Requests\Learning\LearningProductId;
|
|
use App\Http\Requests\Learning\LearningProductStore;
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
|
|
class LearningProductController extends Controller
|
|
{
|
|
private $learningProductService;
|
|
|
|
public function __construct(LearningProductService $learningProductService)
|
|
{
|
|
$this->learningProductService = $learningProductService;
|
|
$this->middleware('auth:sanctum', [
|
|
'except' => [
|
|
'getPublished',
|
|
]
|
|
]);
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$learningProducts = $this->learningProductService->withTrashedAndChildren([
|
|
'filters',
|
|
'filters.filter_item.filter',
|
|
// 'versions',
|
|
'accreditations',
|
|
'notifications',
|
|
])->sortDesc();
|
|
|
|
return response()->json(
|
|
LearningProductResource::collection($learningProducts),
|
|
201,
|
|
);;
|
|
}
|
|
|
|
public function getPublished()
|
|
{
|
|
$withColumnAll = [
|
|
'filters',
|
|
'filters.filter_item.filter',
|
|
'accreditations',
|
|
'accreditations.filters.filter_item',
|
|
'notifications'
|
|
];
|
|
|
|
$learningProductAll = $this->learningProductService->getPublishedWith($withColumnAll)
|
|
->groupBy('code')
|
|
->map(function (Collection $groupedLearningProductAll) {
|
|
return $groupedLearningProductAll->last();
|
|
})
|
|
->sortDesc()
|
|
->flatten(1);
|
|
|
|
return response()->json(
|
|
LearningProductResource::collection($learningProductAll),
|
|
201,
|
|
);
|
|
}
|
|
|
|
public function store(LearningProductStore $request)
|
|
{
|
|
try {
|
|
Log::info('Store method called');
|
|
|
|
$isSuperAdmin = auth()->user()->hasRole('super_admin');
|
|
$isAdmin = auth()->user()->hasRole('admin');
|
|
$isOperator = auth()->user()->hasRole('operator');
|
|
|
|
Log::info('User roles checked', ['isSuperAdmin' => $isSuperAdmin, 'isAdmin' => $isAdmin, 'isOperator' => $isOperator]);
|
|
|
|
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
|
|
return response()->json(['message' => 'You have no rights to do this'], 401);
|
|
}
|
|
|
|
// Is it draft with parent_id marked as published?
|
|
$is_draft = isset($request['parent_id']);
|
|
$is_draft_published = $is_draft && $request['published'];
|
|
|
|
Log::info('Draft status checked', ['is_draft' => $is_draft, 'is_draft_published' => $is_draft_published]);
|
|
|
|
$hasCover = isset($request['cover']) && $request->hasFile('cover');
|
|
$hasTile = isset($request['tile']) && $request->hasFile('tile');
|
|
|
|
Log::info('File status checked', ['hasCover' => $hasCover, 'hasTile' => $hasTile]);
|
|
|
|
// Validate and prepare request data
|
|
$request_data = $request->validated();
|
|
if ($hasCover) {
|
|
$request_data = Arr::except($request_data, ['cover']);
|
|
}
|
|
if ($hasTile) {
|
|
$request_data = Arr::except($request_data, ['tile']);
|
|
}
|
|
|
|
// Publish without parent_id
|
|
if ($is_draft_published) {
|
|
$request_data['parent_id'] = null;
|
|
}
|
|
|
|
$request_data = Arr::except($request_data, ['filtersGrouped', 'synonymsSelected']);
|
|
|
|
// Ensure voor_opleiders has a default value
|
|
if (!isset($request_data['voor_opleiders']) || $request_data['voor_opleiders'] === null) {
|
|
$request_data['voor_opleiders'] = false;
|
|
}
|
|
|
|
Log::info('Request data prepared', ['request_data' => $request_data]);
|
|
|
|
// Save finally the product
|
|
$learning_product = $this->learningProductService->save($request_data);
|
|
|
|
Log::info('Learning product saved', ['learning_product' => $learning_product]);
|
|
|
|
// Get Filter Items passed
|
|
$filter_items = json_decode(html_entity_decode(stripslashes($request['filtersGrouped'])));
|
|
$synonyms_selected = json_decode(html_entity_decode(stripslashes($request['synonymsSelected'])));
|
|
|
|
Log::info('Filters and synonyms decoded', ['filter_items' => $filter_items, 'synonyms_selected' => $synonyms_selected]);
|
|
|
|
if ($synonyms_selected) {
|
|
$learning_product->synonyms()->sync($synonyms_selected);
|
|
}
|
|
|
|
$arrayTmp = [];
|
|
if ($filter_items) {
|
|
foreach ($filter_items as $key => $value) {
|
|
$arrayTmp[] = $value;
|
|
}
|
|
|
|
$filter_items = Arr::collapse($arrayTmp);
|
|
$filter_items = Arr::flatten($arrayTmp);
|
|
|
|
// Saves filter items associations with this learning product
|
|
$learning_product->filters()->delete();
|
|
|
|
foreach ($filter_items as $filter_item_id) {
|
|
$filter_association = new FilterItemsAssociation();
|
|
$filter_association->filter_item_id = $filter_item_id;
|
|
$learning_product->filters()->save($filter_association);
|
|
}
|
|
}
|
|
|
|
// if a file was uploaded as cover or tile, add them
|
|
if ($hasCover) {
|
|
$learning_product->addMediaFromRequest('cover')->toMediaCollection('learning_products_covers');
|
|
}
|
|
if ($hasTile) {
|
|
$learning_product->addMediaFromRequest('tile')->toMediaCollection('learning_products_tiles');
|
|
}
|
|
|
|
if ($is_draft) {
|
|
// 1st draft of the published product
|
|
$original_product_published = $this->learningProductService->get($request['parent_id']);
|
|
|
|
// If no cover has been attached before
|
|
if (!$hasCover && !$learning_product->cover) {
|
|
$image = $original_product_published->getMedia('learning_products_covers')->first();
|
|
|
|
if ($image) {
|
|
$learning_product->copyMedia($image->getPath())->toMediaCollection('learning_products_covers');
|
|
}
|
|
}
|
|
|
|
// If no tile has been attached before
|
|
if (!$hasTile && !$learning_product->tile) {
|
|
$image = $original_product_published->getMedia('learning_products_tiles')->first();
|
|
|
|
if ($image) {
|
|
$learning_product->copyMedia($image->getPath())->toMediaCollection('learning_products_tiles');
|
|
}
|
|
}
|
|
}
|
|
|
|
// ForceDelete the parent if draft published
|
|
if ($is_draft_published && $learning_product) {
|
|
$this->destroy($request['parent_id'], true);
|
|
}
|
|
|
|
Log::info('Learning product processed successfully', ['learning_product' => $learning_product]);
|
|
|
|
// Emit Event to update products
|
|
// broadcast(new \App\Events\ProductsCatalogUpdated);
|
|
|
|
if ($learning_product) {
|
|
return response()->json(new LearningProductResource($learning_product), 201);
|
|
} else {
|
|
return response()->json(['message' => 'Learning Product not found.'], 404);
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error('Error in LearningProductController@store: ' . $e->getMessage(), ['exception' => $e]);
|
|
return response()->json(['message' => 'Internal Server Error'], 500);
|
|
}
|
|
}
|
|
|
|
public function show($id)
|
|
{
|
|
$learning_product = $this->learningProductService->getOneWithChildrenAndTrashed($id, [
|
|
'filters',
|
|
'filters.filter_item.filter',
|
|
'versions',
|
|
'accreditations',
|
|
'notifications',
|
|
'synonyms',
|
|
]);
|
|
|
|
return response()->json(new LearningProductResource($learning_product));
|
|
}
|
|
|
|
public function countAll()
|
|
{
|
|
return response()->json($this->learningProductService->countAll());
|
|
}
|
|
|
|
public function destroy(String $id, $forceDelete = false)
|
|
{
|
|
try {
|
|
Log::info('Destroy method called', ['id' => $id, 'forceDelete' => $forceDelete]);
|
|
|
|
$isSuperAdmin = auth()->user()->hasRole('super_admin');
|
|
$isAdmin = auth()->user()->hasRole('admin');
|
|
$isOperator = auth()->user()->hasRole('operator');
|
|
|
|
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
|
|
return response()->json(['message' => 'You have no rights to do this'], 401);
|
|
}
|
|
|
|
$learning_product = $this->learningProductService->get($id);
|
|
|
|
if (!$learning_product) {
|
|
return response()->json(['message' => 'Learning Product not found.'], 404);
|
|
}
|
|
|
|
// Verwijder gerelateerde records in de versions tabel
|
|
\DB::table('versions')->where('learning_product_id', $id)->delete();
|
|
|
|
if ($forceDelete) {
|
|
$learning_product->forceDelete();
|
|
} else {
|
|
$learning_product->delete();
|
|
}
|
|
|
|
Log::info('Learning product deleted successfully', ['id' => $id]);
|
|
|
|
return response()->json(null, 204);
|
|
} catch (\Exception $e) {
|
|
Log::error('Error in LearningProductController@destroy: ' . $e->getMessage(), ['exception' => $e]);
|
|
return response()->json(['message' => 'Internal Server Error'], 500);
|
|
}
|
|
}
|
|
|
|
public function clone(LearningProductId $request)
|
|
{
|
|
$isSuperAdmin = auth()->user()->hasRole('super_admin');
|
|
$isAdmin = auth()->user()->hasRole('admin');
|
|
$isOperator = auth()->user()->hasRole('operator');
|
|
|
|
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
|
|
return response()->json(['message' => 'You have no rights to do this'], 401);
|
|
}
|
|
|
|
if (!isset($request['product_id']) || !$request['product_id']) {
|
|
return response()->json(['message' => 'Product id missing.'], 400);
|
|
}
|
|
|
|
// get original product to clone
|
|
$original_product = $this->learningProductService->getOneWith($request['product_id'], [
|
|
'filters',
|
|
'filters.filter_item.filter',
|
|
'versions',
|
|
'accreditations',
|
|
'notifications',
|
|
'synonyms',
|
|
]);
|
|
|
|
// Return if not published
|
|
if (!$original_product->published) {
|
|
return response()->json([
|
|
'error' => 'You cannot duplicate a draft'
|
|
], 400);
|
|
}
|
|
|
|
// Return already has a draft
|
|
if ($original_product->draft) {
|
|
return response()->json(['message' => 'There is already a draft for this product'], 400);
|
|
}
|
|
|
|
// set as draft
|
|
$draft = $original_product->replicate();
|
|
$draft->parent_id = $original_product->id;
|
|
$draft->published = false;
|
|
|
|
// clone cover & tiles, finally save
|
|
$cover = $original_product->getMedia('learning_products_covers')->first();
|
|
$tile = $original_product->getMedia('learning_products_tiles')->first();
|
|
|
|
if ($cover) {
|
|
$draft
|
|
->copyMedia($cover->getPath())
|
|
->toMediaCollection('learning_products_covers');
|
|
}
|
|
|
|
if ($tile) {
|
|
$draft
|
|
->copyMedia($tile->getPath())
|
|
->toMediaCollection('learning_products_covers');
|
|
}
|
|
|
|
$draft->save();
|
|
|
|
// TODO: clone accreditations, versions too?
|
|
|
|
// Clone Filter Items
|
|
if ($original_product->filters()) {
|
|
$filter_items_ids = $original_product->filters->pluck('filter_item_id');
|
|
|
|
foreach ($filter_items_ids as $filter_item_id) {
|
|
$filter_association = new FilterItemsAssociation();
|
|
$filter_association->filter_item_id = $filter_item_id;
|
|
$draft->filters()->save($filter_association);
|
|
}
|
|
}
|
|
|
|
// Clone Synonyms
|
|
if ($original_product->synonyms()) {
|
|
$synonyms_ids = $original_product->synonyms->pluck('id');
|
|
$draft->synonyms()->sync($synonyms_ids);
|
|
}
|
|
|
|
return response()->json(null, 201);
|
|
}
|
|
}
|