Initial Laravel API import
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
This commit is contained in:
Joris Slagter
2025-12-02 17:40:21 +01:00
parent 786b6b6a78
commit df155bb13d
341 changed files with 116385 additions and 2 deletions

View File

@@ -0,0 +1,335 @@
<?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']);
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);
}
}