<?php namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Jobs\TranslateCreationJob; use App\Models\Category; use App\Models\Creation; use App\Models\Translation; use App\Models\TranslationKey; use App\Rules\ImageValidationRule; use App\Services\UploadedFilesService; use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; use Illuminate\Validation\Rule; use Illuminate\Validation\Rules\File; use Illuminate\View\View; class CreationController extends Controller { protected array $headerRoutes = [ [ 'route' => 'admin.creations.index', 'label' => 'Liste des créations', 'icon' => 'list', ], [ 'route' => 'admin.creations.create', 'label' => 'Créer une création', 'icon' => 'plus', ], ]; public function __construct(protected UploadedFilesService $uploadedFilesService) {} public function listPage(): View { $creations = Creation::with(['nameTranslationKey', 'category']) ->orderBy('is_highlighted', 'desc') ->orderBy('id', 'desc') ->get(); return view('admin.creations.index', [ 'headerRoutes' => $this->headerRoutes, 'creations' => $creations, ]); } public function createPage(): View { $categories = Category::with('nameTranslationKey.translations') ->get() ->mapWithKeys(function ($category) { $name = $category->nameTranslationKey->translations->firstWhere('locale', 'fr')->text ?? 'N/A'; return [$category->id => $name]; }); return view('admin.creations.edit', [ 'title' => 'Créer une création', 'headerRoutes' => $this->headerRoutes, 'categories' => $categories, ]); } public function editPage(Request $request, int $id): View { $request->validate([ 'lang' => 'sometimes|string|in:fr,en', ]); $lang = $request->input('lang', 'fr'); $creation = Creation::findOrFail($id)->load(['nameTranslationKey.translations', 'shortDescriptionTranslationKey.translations', 'descriptionTranslationKey.translations', 'coverUploadedPicture', 'creationPictures']); $name = $creation->nameTranslationKey->getTranslation($lang); $shortDescription = $creation->shortDescriptionTranslationKey?->getTranslation($lang) ?? ''; $description = $creation->descriptionTranslationKey?->getTranslation($lang) ?? ''; $categories = Category::with('nameTranslationKey.translations') ->get() ->mapWithKeys(function ($category) { $name = $category->nameTranslationKey->translations->firstWhere('locale', 'fr')->text ?? 'N/A'; return [$category->id => $name]; }); return view('admin.creations.edit', [ 'title' => 'Modifier une création', 'headerRoutes' => $this->headerRoutes, 'creation' => $creation, 'name' => $name, 'shortDescription' => $shortDescription, 'description' => $description, 'lang' => $request->input('lang', 'fr'), 'categories' => $categories, ]); } public function store(Request $request): RedirectResponse { $request->validate([ 'lang' => 'required|string|in:fr,en', 'name' => 'required|string', 'slug' => 'required|string', 'category_id' => 'required|exists:categories,id', 'short_description' => 'sometimes|nullable|string', 'description' => 'sometimes|nullable|string', 'completion_date_start' => 'sometimes|nullable|date_format:Y', 'completion_date_end' => 'sometimes|nullable|date_format:Y', 'tags' => 'sometimes|nullable|string', 'cover_image' => [ 'required', new ImageValidationRule, ], 'additional_images' => 'sometimes|array', 'additional_images.*' => File::image() ->max('50mb') ->dimensions(Rule::dimensions()->maxWidth(config('app.imagick.max_width'))->maxHeight(config('app.imagick.max_height'))), 'is_highlighted' => 'sometimes|accepted', ]); $slug = Str::slug($request->input('slug')); if (Creation::where('slug', $slug)->exists()) { return redirect()->route('admin.creations.create') ->withInput() ->with('error', 'Un élément avec ce slug existe déjà.'); } $shortDescription = ! empty($request->input('short_description')) ? $request->input('short_description') : ''; $description = ! empty($request->input('description')) ? $request->input('description') : ''; $nameTranslationKey = TranslationKey::create([ 'key' => 'creation_'.Str::uuid(), ]); $shortDescriptionTranslationKey = TranslationKey::create([ 'key' => 'creation_short_description_'.Str::uuid(), ]); $descriptionTranslationKey = TranslationKey::create([ 'key' => 'creation_description_'.Str::uuid(), ]); Translation::create([ 'translation_key_id' => $nameTranslationKey->id, 'locale' => $request->input('lang'), 'text' => $request->input('name'), ]); Translation::create([ 'translation_key_id' => $shortDescriptionTranslationKey->id, 'locale' => $request->input('lang'), 'text' => $shortDescription, ]); Translation::create([ 'translation_key_id' => $descriptionTranslationKey->id, 'locale' => $request->input('lang'), 'text' => $description, ]); try { $coverUploadedPicture = $this->uploadedFilesService->storeAndOptimizeUploadedPicture($request->file('cover_image')); } catch (Exception $e) { Log::error('Error while storing uploaded picture', [ 'exception' => $e, ]); return redirect()->route('admin.creations.create') ->withInput() ->with('error', 'Une erreur est survenue lors de l\'enregistrement de l\'image.'); } $additionalUploadedPictures = []; if ($request->hasFile('additional_images')) { foreach ($request->file('additional_images') as $additionalImage) { try { $additionalUploadedPictures[] = $this->uploadedFilesService->storeAndOptimizeUploadedPicture($additionalImage); } catch (Exception $e) { Log::error('Error while storing uploaded picture', [ 'exception' => $e, ]); return redirect()->route('admin.creations.create')->withInput() ->with('error', 'Une erreur est survenue lors de l\'enregistrement de l\'image.'); } } } $creation = Creation::create([ 'slug' => $slug, 'category_id' => $request->input('category_id'), 'name_translation_key_id' => $nameTranslationKey->id, 'short_desc_translation_key_id' => $shortDescriptionTranslationKey->id, 'desc_translation_key_id' => $descriptionTranslationKey->id, 'cover_uploaded_picture_id' => $coverUploadedPicture->id, 'completion_date_start' => $request->input('completion_date_start'), 'completion_date_end' => $request->input('completion_date_end'), 'tags' => $request->input('tags'), 'is_highlighted' => $request->boolean('is_highlighted', false), ]); $creation->creationPictures()->attach($additionalUploadedPictures); return redirect()->route('admin.creations.edit', [ 'creation' => $creation->id, 'lang' => $request->input('lang'), ])->with('success', 'Création créée avec succès.'); } public function update(Request $request, int $id): RedirectResponse { $request->validate([ 'lang' => 'required|string|in:fr,en', 'name' => 'required|string', 'slug' => 'required|string', 'category_id' => 'required|exists:categories,id', 'short_description' => 'sometimes|nullable|string', 'description' => 'sometimes|nullable|string', 'completion_date_start' => 'sometimes|nullable|date_format:Y', 'completion_date_end' => 'sometimes|nullable|date_format:Y', 'tags' => 'sometimes|nullable|string', 'cover_image' => [ 'sometimes', 'nullable', new ImageValidationRule, ], 'additional_images' => 'sometimes|array', 'additional_images.*' => File::image() ->max('50mb') ->dimensions(Rule::dimensions()->maxWidth(config('app.imagick.max_width'))->maxHeight(config('app.imagick.max_height'))), 'is_highlighted' => 'sometimes|accepted', ]); $creation = Creation::findOrFail($id); $slug = Str::slug($request->input('slug')); if (Creation::where('slug', $slug)->where('id', '!=', $id)->exists()) { return redirect()->route('admin.creations.edit', [ 'creation' => $creation->id, 'lang' => $request->input('lang'), ]) ->withInput() ->with('error', 'Un élément avec ce slug existe déjà.'); } $shortDescription = ! empty($request->input('short_description')) ? $request->input('short_description') : ''; $description = ! empty($request->input('description')) ? $request->input('description') : ''; $nameTranslationKeyId = $creation->nameTranslationKey->id; $shortDescriptionTranslationKeyId = $creation->shortDescriptionTranslationKey->id; $descriptionTranslationKeyId = $creation->descriptionTranslationKey->id; Translation::updateOrCreate([ 'translation_key_id' => $nameTranslationKeyId, 'locale' => $request->input('lang'), ], [ 'text' => $request->input('name'), ]); Translation::updateOrCreate([ 'translation_key_id' => $shortDescriptionTranslationKeyId, 'locale' => $request->input('lang'), ], [ 'text' => $shortDescription, ]); Translation::updateOrCreate([ 'translation_key_id' => $descriptionTranslationKeyId, 'locale' => $request->input('lang'), ], [ 'text' => $description, ]); if ($request->hasFile('cover_image')) { try { $coverUploadedPicture = $this->uploadedFilesService->storeAndOptimizeUploadedPicture($request->file('cover_image')); } catch (Exception $e) { Log::error('Error while storing uploaded picture', [ 'exception' => $e, ]); return redirect()->route('admin.creations.edit', [ 'creation' => $creation->id, 'lang' => $request->input('lang'), ]) ->withInput() ->with('error', 'Une erreur est survenue lors de l\'enregistrement de l\'image.'); } $creation->coverUploadedPicture()->associate($coverUploadedPicture); } if ($request->hasFile('additional_images')) { $additionalUploadedPictures = []; foreach ($request->file('additional_images') as $additionalImage) { try { $additionalUploadedPictures[] = $this->uploadedFilesService->storeAndOptimizeUploadedPicture($additionalImage); } catch (Exception $e) { Log::error('Error while storing uploaded picture', [ 'exception' => $e, ]); return redirect()->route('admin.creations.edit', [ 'creation' => $creation->id, 'lang' => $request->input('lang'), ]) ->withInput() ->with('error', 'Une erreur est survenue lors de l\'enregistrement de l\'image.'); } } $creation->creationPictures()->attach($additionalUploadedPictures); } $creation->slug = $slug; $creation->category_id = $request->input('category_id'); $creation->completion_date_start = $request->input('completion_date_start'); $creation->completion_date_end = $request->input('completion_date_end'); $creation->tags = $request->input('tags'); $creation->is_highlighted = $request->boolean('is_highlighted', false); $creation->save(); return redirect()->route('admin.creations.edit', [ 'creation' => $creation->id, 'lang' => $request->input('lang')]) ->with('success', 'Création mise à jour avec succès.'); } public function delete(int $id): RedirectResponse { $creation = Creation::findOrFail($id); $creation->delete(); return redirect()->route('admin.creations.index') ->with('success', 'Création supprimée avec succès.'); } public function removeAdditionalImage(int $creationId, int $uploadedPictureId): JsonResponse { $creation = Creation::findOrFail($creationId); $creation->creationPictures()->detach($uploadedPictureId); return response()->json([ 'success' => true, ]); } public function translateWithAi(int $creationId): JsonResponse { $creation = Creation::findOrFail($creationId); $job = new TranslateCreationJob($creation); dispatch($job); return response()->json([ 'success' => true, ]); } }