feat: meal post ingredients
This commit is contained in:
parent
7916e7f718
commit
7a907f2b17
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum IngredientUnit: string
|
||||||
|
{
|
||||||
|
case GRAM = 'g';
|
||||||
|
case KILOGRAM = 'kg';
|
||||||
|
|
||||||
|
case MILLILITER = 'ml';
|
||||||
|
case LITER = 'l';
|
||||||
|
|
||||||
|
case PIECE = 'piece';
|
||||||
|
case TEASPOON = 'tsp';
|
||||||
|
case TABLESPOON = 'tbsp';
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ 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\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class MealPostController extends Controller
|
class MealPostController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -66,12 +67,26 @@ class MealPostController extends Controller
|
||||||
|
|
||||||
public function store(MealPostsRequest $request): JsonResponse
|
public function store(MealPostsRequest $request): JsonResponse
|
||||||
{
|
{
|
||||||
|
$data = $this->getValidatedDataWithImageUrl($request);
|
||||||
|
$ingredients = $data['ingredients'] ?? [];
|
||||||
|
|
||||||
|
unset($data['ingredients']);
|
||||||
|
|
||||||
|
$mealPost = DB::transaction(function () use ($data, $ingredients, $request): MealPosts {
|
||||||
$mealPost = MealPosts::create([
|
$mealPost = MealPosts::create([
|
||||||
...$this->getValidatedDataWithImageUrl($request),
|
...$data,
|
||||||
'user_id' => $request->user()->getKey(),
|
'user_id' => $request->user()->getKey(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if ($ingredients !== []) {
|
||||||
|
$mealPost->ingredients()->createMany($ingredients);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $mealPost;
|
||||||
|
});
|
||||||
|
|
||||||
$mealPost->setRelation('user', $request->user());
|
$mealPost->setRelation('user', $request->user());
|
||||||
|
$mealPost->loadMissing('ingredients');
|
||||||
|
|
||||||
return (new MealPostsResource($mealPost))
|
return (new MealPostsResource($mealPost))
|
||||||
->response()
|
->response()
|
||||||
|
|
@ -82,16 +97,36 @@ class MealPostController extends Controller
|
||||||
{
|
{
|
||||||
$this->abortIfNotOwner($request, $mealPost);
|
$this->abortIfNotOwner($request, $mealPost);
|
||||||
|
|
||||||
return new MealPostsResource($mealPost->loadMissing('user:id,name,avatar_url'));
|
return new MealPostsResource($mealPost->loadMissing('user:id,name,avatar_url', 'ingredients'));
|
||||||
}
|
}
|
||||||
|
|
||||||
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($this->getValidatedDataWithImageUrl($request));
|
$data = $this->getValidatedDataWithImageUrl($request);
|
||||||
|
$shouldSyncIngredients = array_key_exists('ingredients', $data);
|
||||||
|
$ingredients = $data['ingredients'] ?? [];
|
||||||
|
|
||||||
return new MealPostsResource($mealPost->refresh()->loadMissing('user:id,name,avatar_url'));
|
unset($data['ingredients']);
|
||||||
|
|
||||||
|
$mealPost = DB::transaction(function () use ($data, $ingredients, $mealPost, $shouldSyncIngredients): MealPosts {
|
||||||
|
if ($data !== []) {
|
||||||
|
$mealPost->update($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($shouldSyncIngredients) {
|
||||||
|
$mealPost->ingredients()->delete();
|
||||||
|
|
||||||
|
if ($ingredients !== []) {
|
||||||
|
$mealPost->ingredients()->createMany($ingredients);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $mealPost->refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
return new MealPostsResource($mealPost->loadMissing('user:id,name,avatar_url', 'ingredients'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy(Request $request, MealPosts $mealPost): Response
|
public function destroy(Request $request, MealPosts $mealPost): Response
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Enums\IngredientUnit;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class MealPostIngredientsRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'meal_posts_id' => ['required', 'exists:meal_posts,id'],
|
||||||
|
'position' => ['required', 'integer'],
|
||||||
|
'ingredient' => ['required', 'string'],
|
||||||
|
'unit' => ['required', Rule::enum(IngredientUnit::class)],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Enums\IngredientUnit;
|
||||||
use App\Enums\MealPostType;
|
use App\Enums\MealPostType;
|
||||||
use App\Enums\MealPostVisibility;
|
use App\Enums\MealPostVisibility;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
@ -25,6 +26,11 @@ class MealPostsRequest extends FormRequest
|
||||||
'eaten_at' => [$isCreating ? 'required' : 'sometimes', 'date'],
|
'eaten_at' => [$isCreating ? 'required' : 'sometimes', 'date'],
|
||||||
'type' => [$isCreating ? 'required' : 'sometimes', Rule::enum(MealPostType::class)],
|
'type' => [$isCreating ? 'required' : 'sometimes', Rule::enum(MealPostType::class)],
|
||||||
'visibility' => ['sometimes', Rule::enum(MealPostVisibility::class)],
|
'visibility' => ['sometimes', Rule::enum(MealPostVisibility::class)],
|
||||||
|
'ingredients' => ['sometimes', 'array'],
|
||||||
|
'ingredients.*' => ['required', 'array:position,ingredient,unit'],
|
||||||
|
'ingredients.*.position' => ['required', 'integer', 'min:0'],
|
||||||
|
'ingredients.*.ingredient' => ['required', 'string', 'max:255'],
|
||||||
|
'ingredients.*.unit' => ['required', Rule::enum(IngredientUnit::class)],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use App\Models\MealPostIngredients;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
/** @mixin MealPostIngredients */
|
||||||
|
class MealPostIngredientsResource extends JsonResource
|
||||||
|
{
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'position' => $this->position,
|
||||||
|
'ingredient' => $this->ingredient,
|
||||||
|
'unit' => $this->unit,
|
||||||
|
'created_at' => $this->created_at,
|
||||||
|
'updated_at' => $this->updated_at,
|
||||||
|
|
||||||
|
'meal_posts_id' => $this->meal_posts_id,
|
||||||
|
|
||||||
|
'mealPosts' => new MealPostsResource($this->whenLoaded('mealPosts')),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ class MealPostsResource extends JsonResource
|
||||||
'eatenAt' => $this->eaten_at,
|
'eatenAt' => $this->eaten_at,
|
||||||
'createdAt' => $this->created_at,
|
'createdAt' => $this->created_at,
|
||||||
'updatedAt' => $this->updated_at,
|
'updatedAt' => $this->updated_at,
|
||||||
|
'ingredients' => MealPostIngredientsResource::collection($this->whenLoaded('ingredients')),
|
||||||
|
|
||||||
'user' => [
|
'user' => [
|
||||||
'name' => $user?->name,
|
'name' => $user?->name,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\IngredientUnit;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
|
class MealPostIngredients extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'meal_posts_id',
|
||||||
|
'position',
|
||||||
|
'ingredient',
|
||||||
|
'unit',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function mealPosts(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(MealPosts::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'unit' => IngredientUnit::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ 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;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
class MealPosts extends Model
|
class MealPosts extends Model
|
||||||
|
|
@ -37,12 +38,17 @@ class MealPosts extends Model
|
||||||
return $this->belongsTo(User::class);
|
return $this->belongsTo(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function ingredients(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(MealPostIngredients::class)->orderBy('position');
|
||||||
|
}
|
||||||
|
|
||||||
protected function casts(): array
|
protected function casts(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'eaten_at' => 'datetime',
|
'eaten_at' => 'datetime',
|
||||||
'visibility' => MealPostVisibility::class,
|
'visibility' => MealPostVisibility::class,
|
||||||
'type' => MealPostType::class
|
'type' => MealPostType::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\MealPostIngredients;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||||
|
|
||||||
|
class MealPostIngredientsPolicy
|
||||||
|
{
|
||||||
|
use HandlesAuthorization;
|
||||||
|
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function view(User $user, MealPostIngredients $mealPostIngredients): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(User $user, MealPostIngredients $mealPostIngredients): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(User $user, MealPostIngredients $mealPostIngredients): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function restore(User $user, MealPostIngredients $mealPostIngredients): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function forceDelete(User $user, MealPostIngredients $mealPostIngredients): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,11 +13,11 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'default' => 'openai',
|
'default' => 'deepseek',
|
||||||
'default_for_images' => 'gemini',
|
'default_for_images' => 'gemini',
|
||||||
'default_for_audio' => 'openai',
|
'default_for_audio' => 'openai',
|
||||||
'default_for_transcription' => 'openai',
|
'default_for_transcription' => 'openai',
|
||||||
'default_for_embeddings' => 'openai',
|
'default_for_embeddings' => 'deepseek',
|
||||||
'default_for_reranking' => 'cohere',
|
'default_for_reranking' => 'cohere',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('meal_post_ingredients', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignUlid('meal_posts_id')->constrained('meal_posts')->cascadeOnDelete();
|
||||||
|
$table->integer('position');
|
||||||
|
$table->string('ingredient');
|
||||||
|
$table->string('unit');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('meal_post_ingredients');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Enums\IngredientUnit;
|
||||||
|
use App\Enums\MealPostType;
|
||||||
|
use App\Models\MealPosts;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Laravel\Sanctum\Sanctum;
|
||||||
|
|
||||||
|
uses(RefreshDatabase::class);
|
||||||
|
|
||||||
|
it('creates a meal post with ingredients', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
Sanctum::actingAs($user);
|
||||||
|
|
||||||
|
$response = $this->postJson('/api/meal-posts', [
|
||||||
|
'image_url' => 'https://example.com/meal.jpg',
|
||||||
|
'title' => 'Bowl saumon avocat',
|
||||||
|
'eaten_at' => '2026-05-16T12:00:00.000Z',
|
||||||
|
'type' => MealPostType::LUNCH->value,
|
||||||
|
'ingredients' => [
|
||||||
|
[
|
||||||
|
'position' => 1,
|
||||||
|
'ingredient' => 'Riz',
|
||||||
|
'unit' => IngredientUnit::GRAM->value,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'position' => 2,
|
||||||
|
'ingredient' => 'Saumon',
|
||||||
|
'unit' => IngredientUnit::GRAM->value,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response
|
||||||
|
->assertCreated()
|
||||||
|
->assertJsonPath('data.ingredients.0.ingredient', 'Riz')
|
||||||
|
->assertJsonPath('data.ingredients.0.unit', IngredientUnit::GRAM->value)
|
||||||
|
->assertJsonPath('data.ingredients.1.ingredient', 'Saumon');
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('meal_post_ingredients', [
|
||||||
|
'meal_posts_id' => $response->json('data.id'),
|
||||||
|
'position' => 1,
|
||||||
|
'ingredient' => 'Riz',
|
||||||
|
'unit' => IngredientUnit::GRAM->value,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('validates meal post ingredients', function () {
|
||||||
|
Sanctum::actingAs(User::factory()->create());
|
||||||
|
|
||||||
|
$response = $this->postJson('/api/meal-posts', [
|
||||||
|
'image_url' => 'https://example.com/meal.jpg',
|
||||||
|
'title' => 'Bowl saumon avocat',
|
||||||
|
'eaten_at' => '2026-05-16T12:00:00.000Z',
|
||||||
|
'type' => MealPostType::LUNCH->value,
|
||||||
|
'ingredients' => [
|
||||||
|
[
|
||||||
|
'position' => -1,
|
||||||
|
'ingredient' => '',
|
||||||
|
'unit' => 'cup',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response
|
||||||
|
->assertUnprocessable()
|
||||||
|
->assertJsonValidationErrors([
|
||||||
|
'ingredients.0.position',
|
||||||
|
'ingredients.0.ingredient',
|
||||||
|
'ingredients.0.unit',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('replaces meal post ingredients when updating a meal post', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$mealPost = MealPosts::factory()->for($user, 'user')->create();
|
||||||
|
$mealPost->ingredients()->createMany([
|
||||||
|
[
|
||||||
|
'position' => 1,
|
||||||
|
'ingredient' => 'Riz',
|
||||||
|
'unit' => IngredientUnit::GRAM,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'position' => 2,
|
||||||
|
'ingredient' => 'Saumon',
|
||||||
|
'unit' => IngredientUnit::GRAM,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
Sanctum::actingAs($user);
|
||||||
|
|
||||||
|
$response = $this->patchJson("/api/meal-posts/{$mealPost->id}", [
|
||||||
|
'ingredients' => [
|
||||||
|
[
|
||||||
|
'position' => 1,
|
||||||
|
'ingredient' => 'Pates',
|
||||||
|
'unit' => IngredientUnit::GRAM->value,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'position' => 2,
|
||||||
|
'ingredient' => 'Huile olive',
|
||||||
|
'unit' => IngredientUnit::TABLESPOON->value,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('data.ingredients.0.ingredient', 'Pates')
|
||||||
|
->assertJsonPath('data.ingredients.1.unit', IngredientUnit::TABLESPOON->value);
|
||||||
|
|
||||||
|
$this->assertDatabaseMissing('meal_post_ingredients', [
|
||||||
|
'meal_posts_id' => $mealPost->id,
|
||||||
|
'ingredient' => 'Riz',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('meal_post_ingredients', [
|
||||||
|
'meal_posts_id' => $mealPost->id,
|
||||||
|
'position' => 1,
|
||||||
|
'ingredient' => 'Pates',
|
||||||
|
'unit' => IngredientUnit::GRAM->value,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps existing ingredients when updating a meal post without ingredients', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$mealPost = MealPosts::factory()->for($user, 'user')->create([
|
||||||
|
'title' => 'Ancien titre',
|
||||||
|
]);
|
||||||
|
$mealPost->ingredients()->create([
|
||||||
|
'position' => 1,
|
||||||
|
'ingredient' => 'Riz',
|
||||||
|
'unit' => IngredientUnit::GRAM,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Sanctum::actingAs($user);
|
||||||
|
|
||||||
|
$response = $this->patchJson("/api/meal-posts/{$mealPost->id}", [
|
||||||
|
'title' => 'Nouveau titre',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('data.title', 'Nouveau titre')
|
||||||
|
->assertJsonPath('data.ingredients.0.ingredient', 'Riz');
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('meal_post_ingredients', [
|
||||||
|
'meal_posts_id' => $mealPost->id,
|
||||||
|
'ingredient' => 'Riz',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes meal post ingredients when updating with an empty ingredients list', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$mealPost = MealPosts::factory()->for($user, 'user')->create();
|
||||||
|
$mealPost->ingredients()->create([
|
||||||
|
'position' => 1,
|
||||||
|
'ingredient' => 'Riz',
|
||||||
|
'unit' => IngredientUnit::GRAM,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Sanctum::actingAs($user);
|
||||||
|
|
||||||
|
$response = $this->patchJson("/api/meal-posts/{$mealPost->id}", [
|
||||||
|
'ingredients' => [],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonCount(0, 'data.ingredients');
|
||||||
|
|
||||||
|
$this->assertDatabaseMissing('meal_post_ingredients', [
|
||||||
|
'meal_posts_id' => $mealPost->id,
|
||||||
|
]);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue