feat: save meal

This commit is contained in:
Leon Morival 2026-05-15 22:43:58 +02:00
parent 5ee10cb8b5
commit 425d0d2498
5 changed files with 45 additions and 10 deletions

View File

@ -9,6 +9,7 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection; use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
class MealPostController extends Controller class MealPostController extends Controller
{ {
@ -18,6 +19,7 @@ class MealPostController extends Controller
$mealPosts = MealPosts::query() $mealPosts = MealPosts::query()
->where('user_id', $request->user()->getKey()) ->where('user_id', $request->user()->getKey())
->with('user:id,name,avatar_url')
->latest('eaten_at') ->latest('eaten_at')
->paginate($perPage) ->paginate($perPage)
->withQueryString(); ->withQueryString();
@ -28,10 +30,12 @@ class MealPostController extends Controller
public function store(MealPostsRequest $request): JsonResponse public function store(MealPostsRequest $request): JsonResponse
{ {
$mealPost = MealPosts::create([ $mealPost = MealPosts::create([
...$request->validated(), ...$this->getValidatedDataWithImageUrl($request),
'user_id' => $request->user()->getKey(), 'user_id' => $request->user()->getKey(),
]); ]);
$mealPost->setRelation('user', $request->user());
return (new MealPostsResource($mealPost)) return (new MealPostsResource($mealPost))
->response() ->response()
->setStatusCode(201); ->setStatusCode(201);
@ -41,16 +45,16 @@ class MealPostController extends Controller
{ {
$this->abortIfNotOwner($request, $mealPost); $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 public function update(MealPostsRequest $request, MealPosts $mealPost): MealPostsResource
{ {
$this->abortIfNotOwner($request, $mealPost); $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 public function destroy(Request $request, MealPosts $mealPost): Response
@ -67,4 +71,18 @@ class MealPostController extends Controller
abort_unless($request->user(), 401); abort_unless($request->user(), 401);
abort_unless($mealPost->user_id === $request->user()->getKey(), 404); 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;
}
} }

View File

@ -9,7 +9,8 @@ class MealPostsRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ 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'], 'caption' => ['nullable', 'string', 'max:1000'],
'calories' => ['nullable', 'integer', 'min:0'], 'calories' => ['nullable', 'integer', 'min:0'],
'proteins' => ['nullable', 'numeric', 'min:0'], 'proteins' => ['nullable', 'numeric', 'min:0'],
@ -24,4 +25,12 @@ class MealPostsRequest extends FormRequest
{ {
return true; 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.",
];
}
} }

View File

@ -5,12 +5,15 @@ namespace App\Http\Resources;
use App\Models\MealPosts; use App\Models\MealPosts;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Storage;
/** @mixin MealPosts */ /** @mixin MealPosts */
class MealPostsResource extends JsonResource class MealPostsResource extends JsonResource
{ {
public function toArray(Request $request): array public function toArray(Request $request): array
{ {
$user = $this->user;
return [ return [
'id' => $this->id, 'id' => $this->id,
'imageUrl' => $this->image_url, 'imageUrl' => $this->image_url,
@ -24,7 +27,11 @@ class MealPostsResource extends JsonResource
'createdAt' => $this->created_at, 'createdAt' => $this->created_at,
'updatedAt' => $this->updated_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,
],
]; ];
} }
} }

View File

@ -2,6 +2,7 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -9,7 +10,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
class MealPosts extends Model class MealPosts extends Model
{ {
use HasFactory, SoftDeletes; use HasFactory, HasUlids, SoftDeletes;
protected $fillable = [ protected $fillable = [
'user_id', 'user_id',
@ -31,7 +32,7 @@ class MealPosts extends Model
protected function casts(): array protected function casts(): array
{ {
return [ return [
'eaten_at' => 'timestamp', 'eaten_at' => 'datetime',
]; ];
} }
} }

View File

@ -8,9 +8,9 @@ return new class extends Migration {
public function up(): void public function up(): void
{ {
Schema::create('meal_posts', function (Blueprint $table) { Schema::create('meal_posts', function (Blueprint $table) {
$table->id(); $table->ulid('id')->primary();
$table->foreignUlid('user_id')->constrained('users')->cascadeOnDelete(); $table->foreignUlid('user_id')->constrained('users')->cascadeOnDelete();
$table->string('image_url'); $table->string('image_url', 2048);
$table->text('caption')->nullable(); $table->text('caption')->nullable();
$table->integer('calories')->nullable(); $table->integer('calories')->nullable();
$table->decimal('proteins',8,2)->nullable(); $table->decimal('proteins',8,2)->nullable();