From 425d0d2498aec2e52a29814b269514a1f6a88d39 Mon Sep 17 00:00:00 2001 From: Leon Morival Date: Fri, 15 May 2026 22:43:58 +0200 Subject: [PATCH] feat: save meal --- app/Http/Controllers/MealPostController.php | 26 ++++++++++++++++--- app/Http/Requests/MealPostsRequest.php | 11 +++++++- app/Http/Resources/MealPostsResource.php | 9 ++++++- app/Models/MealPosts.php | 5 ++-- ...6_05_15_111236_create_meal_posts_table.php | 4 +-- 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/MealPostController.php b/app/Http/Controllers/MealPostController.php index 29911ea..9e31dbd 100644 --- a/app/Http/Controllers/MealPostController.php +++ b/app/Http/Controllers/MealPostController.php @@ -9,6 +9,7 @@ use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\AnonymousResourceCollection; use Illuminate\Http\Response; +use Illuminate\Support\Facades\Storage; class MealPostController extends Controller { @@ -18,6 +19,7 @@ class MealPostController extends Controller $mealPosts = MealPosts::query() ->where('user_id', $request->user()->getKey()) + ->with('user:id,name,avatar_url') ->latest('eaten_at') ->paginate($perPage) ->withQueryString(); @@ -28,10 +30,12 @@ class MealPostController extends Controller public function store(MealPostsRequest $request): JsonResponse { $mealPost = MealPosts::create([ - ...$request->validated(), + ...$this->getValidatedDataWithImageUrl($request), 'user_id' => $request->user()->getKey(), ]); + $mealPost->setRelation('user', $request->user()); + return (new MealPostsResource($mealPost)) ->response() ->setStatusCode(201); @@ -41,16 +45,16 @@ class MealPostController extends Controller { $this->abortIfNotOwner($request, $mealPost); - return new MealPostsResource($mealPost); + return new MealPostsResource($mealPost->loadMissing('user:id,name,avatar_url')); } public function update(MealPostsRequest $request, MealPosts $mealPost): MealPostsResource { $this->abortIfNotOwner($request, $mealPost); - $mealPost->update($request->validated()); + $mealPost->update($this->getValidatedDataWithImageUrl($request)); - return new MealPostsResource($mealPost->refresh()); + return new MealPostsResource($mealPost->refresh()->loadMissing('user:id,name,avatar_url')); } public function destroy(Request $request, MealPosts $mealPost): Response @@ -67,4 +71,18 @@ class MealPostController extends Controller abort_unless($request->user(), 401); abort_unless($mealPost->user_id === $request->user()->getKey(), 404); } + + private function getValidatedDataWithImageUrl(MealPostsRequest $request): array + { + $data = $request->validated(); + + if ($request->hasFile('image')) { + $path = $request->file('image')->store('meal-posts', 'public'); + $data['image_url'] = asset(Storage::url($path)); + } + + unset($data['image']); + + return $data; + } } diff --git a/app/Http/Requests/MealPostsRequest.php b/app/Http/Requests/MealPostsRequest.php index 4f6638b..56023a0 100644 --- a/app/Http/Requests/MealPostsRequest.php +++ b/app/Http/Requests/MealPostsRequest.php @@ -9,7 +9,8 @@ class MealPostsRequest extends FormRequest public function rules(): array { return [ - 'image_url' => ['required', 'string', 'url', 'max:255'], + 'image' => ['sometimes', 'nullable', 'image', 'max:4096'], + 'image_url' => ['required_without:image', 'nullable', 'string', 'url', 'max:2048'], 'caption' => ['nullable', 'string', 'max:1000'], 'calories' => ['nullable', 'integer', 'min:0'], 'proteins' => ['nullable', 'numeric', 'min:0'], @@ -24,4 +25,12 @@ class MealPostsRequest extends FormRequest { return true; } + + public function messages(): array + { + return [ + 'image.max' => "L'image ne doit pas dépasser 4 Mo.", + 'image_url.required_without' => "Ajoute une image au repas.", + ]; + } } diff --git a/app/Http/Resources/MealPostsResource.php b/app/Http/Resources/MealPostsResource.php index 6e0d4bd..a83a33c 100644 --- a/app/Http/Resources/MealPostsResource.php +++ b/app/Http/Resources/MealPostsResource.php @@ -5,12 +5,15 @@ namespace App\Http\Resources; use App\Models\MealPosts; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; +use Illuminate\Support\Facades\Storage; /** @mixin MealPosts */ class MealPostsResource extends JsonResource { public function toArray(Request $request): array { + $user = $this->user; + return [ 'id' => $this->id, 'imageUrl' => $this->image_url, @@ -24,7 +27,11 @@ class MealPostsResource extends JsonResource 'createdAt' => $this->created_at, 'updatedAt' => $this->updated_at, - 'userId' => $this->user_id, + 'user' => [ + 'name' => $user?->name, + 'avatarUrl' => $user?->avatar_url ? asset(Storage::url($user->avatar_url)) : null, + 'id' => $user->id, + ], ]; } } diff --git a/app/Models/MealPosts.php b/app/Models/MealPosts.php index 5577eca..935fb83 100644 --- a/app/Models/MealPosts.php +++ b/app/Models/MealPosts.php @@ -2,6 +2,7 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -9,7 +10,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; class MealPosts extends Model { - use HasFactory, SoftDeletes; + use HasFactory, HasUlids, SoftDeletes; protected $fillable = [ 'user_id', @@ -31,7 +32,7 @@ class MealPosts extends Model protected function casts(): array { return [ - 'eaten_at' => 'timestamp', + 'eaten_at' => 'datetime', ]; } } diff --git a/database/migrations/2026_05_15_111236_create_meal_posts_table.php b/database/migrations/2026_05_15_111236_create_meal_posts_table.php index 68b5f80..a7cc196 100644 --- a/database/migrations/2026_05_15_111236_create_meal_posts_table.php +++ b/database/migrations/2026_05_15_111236_create_meal_posts_table.php @@ -8,9 +8,9 @@ return new class extends Migration { public function up(): void { Schema::create('meal_posts', function (Blueprint $table) { - $table->id(); + $table->ulid('id')->primary(); $table->foreignUlid('user_id')->constrained('users')->cascadeOnDelete(); - $table->string('image_url'); + $table->string('image_url', 2048); $table->text('caption')->nullable(); $table->integer('calories')->nullable(); $table->decimal('proteins',8,2)->nullable();