0

我正在构建一个自动创建购物清单的膳食计划器,其中一个关键是能够在食谱上设置成分的数量。我通过在Recipe -> Ingredients. 这是在我的中间枢轴模型成分配方中定义的,它存储配方所需的单位和数量。

Recipe -> IngredientRecipe(Quantity,Unit) -> Ingredient

我在设置每种成分的数量和单位时遇到问题。我知道我可以在创建它们之后单独循环和迭代它们;但是,这感觉不对,我宁愿在一个查询中完成。

我有点坚持如何进行此操作。我会认为用设置的值初始化一堆成分配方枢轴并将它们保存到配方就足够了,但枢轴值不会被保留。这一切都是在 PHP 8.1 上使用 Laravel 9.2 构建的。

食谱.php

...

public function ingredients(): BelongsToMany
{
    return $this->belongsToMany(Ingredient::class)
        ->using(IngredientRecipe::class);
}

成分配方.php

...

protected $fillable = [
    'recipe_id',
    'ingredient_id',
    'quantity',
    'unit_id',
];

public function recipe(): BelongsTo
{
    return $this->belongsTo(Recipe::class);
}

public function ingredient(): BelongsTo
{
    return $this->belongsTo(Ingredient::class);
}

public function unit(): BelongsTo
{
    return $this->belongsTo(Unit::class);
}

更新成分配方.php

...

    return [
        'unit' => 'required|array',
        'quantity' => 'required|array',
        'unit.*' => 'integer|exists:units,id',
        'quantity.*' => 'numeric|digits_between:0,999',
    ];

成分配方控制器.php

...

public function update(Recipe $recipe, UpdateIngredientRecipe $request): RedirectResponse
{
    $pivots = collect($request->validated('quantity'))
        ->map(function (float $quantity, int $ingredient_id) use ($request, $recipe): IngredientRecipe {

            $payload = [
                'ingredient_id' => $ingredient_id,
                'recipe_id' => $recipe->id,
                'quantity' => $quantity,
                'unit_id' => (int) $request->validated('unit')[$ingredient_id],
            ];

            return IngredientRecipe::make($payload);
        });

    $recipe->ingredients()->attach($pivots->pluck('ingredient_id'), $pivots->first()->toArray());
    dd(__METHOD__, $recipe->fresh('ingredients')->ingredients);

    return redirect()->route('recipe.get', $recipe);
}
4

2 回答 2

0

所以我自己解决了这个问题。回想起来似乎很痛苦,但我希望这对将来陷入类似事情的人有所帮助。

我现在正在构建由成分ID键入的枢轴属性数组

    public function update(Recipe $recipe, UpdateIngredientRecipe $request): RedirectResponse
    {
        $payload = [];
        $pivots = collect($request->validated('quantity'))
            ->each(function (float $quantity, int $ingredient_id) use ($request, $recipe, &$payload) {

                $payload[$ingredient_id] = [
                    'recipe_id' => $recipe->id,
                    'quantity' => $quantity,
                    'unit_id'  => (int) $request->validated('unit')[$ingredient_id],
                ];
            });

        dump($recipe->ingredients()->sync($payload));
        dd($recipe->fresh()->ingredients);

        return redirect()->route('recipe.get', $recipe);
    }

所以从某种意义上说,我现在正在做的是:

$ingredientsToSync = [
    $ingredient_id => [
        'recipe_id' => $recipe->id,
        'quantity' => $quantity,
        'unit_id'  => (int) $request->validated('unit')[$ingredient_id],
    ], 
    ... // other ingredients below
];

$recipe->ingredients()->sync($ingredientsToSync);

还值得注意的是,我需要更新我在Recipe中的关系定义才能获得枢轴值

    // Recipe.php
    ...
    public function ingredients(): BelongsToMany
    {
        return $this->belongsToMany(Ingredient::class)
            ->using(IngredientRecipe::class)
            ->withPivot(['quantity', 'unit_id']);
    }
于 2022-03-01T13:31:21.263 回答
0

这对于您的用例应该足够了:

public function update(Recipe $recipe, UpdateIngredientRecipe $request): RedirectResponse
    {
        $pivots = collect($request->validated('quantity'))
            ->map(function (float $quantity, int $ingredient_id) use ($request, $recipe): IngredientRecipe {

                return [
                    'ingredient_id' => $ingredient_id,
                    'recipe_id' => $recipe->id,
                    'quantity' => $quantity,
                    'unit_id'  => (int) $request->validated('unit')[$ingredient_id],
                ];
        });
        IngredientRecipe::createMany($pivots);

        return redirect()->route('recipe.get', $recipe);
    }

由于关系数据已经在数据透视数组中,因此您也不需要附加它们。createMany可能能够大量插入行并节省多个数据库/服务器往返。

于 2022-03-01T13:56:47.940 回答