with('recipes', Recipe::all()->sortBy('name')); } /** * Show the form for creating a new resource. * * @return \Illuminate\Contracts\View\View */ public function create(): View { return $this->edit(new Recipe()); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\RedirectResponse * * @throws \Throwable */ public function store(Request $request): RedirectResponse { return $this->update($request, new Recipe()); } /** * Display the specified resource. * * @param \App\Models\Recipe $recipe * @return \Illuminate\Contracts\View\View */ public function show(Recipe $recipe): View { return view('recipes.show')->with('recipe', $recipe); } /** * Show the form for editing the specified resource. * * @param \App\Models\Recipe $recipe * @return \Illuminate\Contracts\View\View */ public function edit(Recipe $recipe): View { // Pre-populate ingredients from form data or current recipe. $ingredients = []; if ($old = old('ingredients')) { foreach ($old['id'] as $key => $food_id) { if (empty($food_id)) { continue; } $ingredients[] = [ 'amount' => $old['amount'][$key], 'unit' => $old['unit'][$key], 'food_id' => $food_id, 'food_name' => $old['name'][$key], 'detail' => $old['detail'][$key], ]; } } else { foreach ($recipe->foodAmounts as $foodAmount) { $ingredients[] = [ 'amount' => $foodAmount->amount_formatted, 'unit' => $foodAmount->unit, 'food_id' => $foodAmount->food->id, 'food_name' => $foodAmount->food->name, 'detail' => $foodAmount->detail, ]; } } return view('recipes.edit') ->with('recipe', $recipe) ->with('ingredients', $ingredients) ->with('ingredients_units', new Collection([ ['value' => 'tsp', 'label' => 'tsp.'], ['value' => 'tbsp', 'label' => 'tbsp.'], ['value' => 'cup', 'label' => 'cup'], ['value' => 'oz', 'label' => 'oz'], ['value' => 'grams', 'label' => 'g'], ])); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param \App\Models\Recipe $recipe * * @return \Illuminate\Http\RedirectResponse * * @throws \Throwable */ public function update(Request $request, Recipe $recipe): RedirectResponse { $input = $request->validate([ 'name' => 'required|string', 'description' => 'nullable|string', 'source' => 'nullable|string', 'servings' => 'required|numeric', 'ingredients.amount' => ['required', 'array', new ArrayNotEmpty], 'ingredients.amount.*' => ['required_with:ingredients.id.*', 'nullable', new StringIsDecimalOrFraction], 'ingredients.unit' => ['required', 'array'], 'ingredients.unit.*' => 'nullable|string', 'ingredients.detail' => ['required', 'array'], 'ingredients.detail.*' => 'nullable|string', 'ingredients.id' => ['required', 'array', new ArrayNotEmpty], 'ingredients.id.*' => 'required_with:ingredients.amount.*|nullable|exists:App\Models\Food,id', 'steps' => ['required', 'array', new ArrayNotEmpty], 'steps.*' => 'nullable|string', ]); $recipe->fill([ 'name' => Str::lower($input['name']), 'description' => $input['description'], 'source' => $input['source'], 'servings' => (int) $input['servings'], ]); try { DB::transaction(function () use ($recipe, $input) { if (!$recipe->save()) { return; } $food_amounts = []; $weight = 0; // TODO: Handle removals. foreach (array_filter($input['ingredients']['id']) as $key => $food_id) { $food_amounts[$key] = $recipe->foodAmounts[$key] ?? new FoodAmount(); $food_amounts[$key]->fill([ 'amount' => Number::floatFromString($input['ingredients']['amount'][$key]), 'unit' => $input['ingredients']['unit'][$key], 'detail' => $input['ingredients']['detail'][$key], 'weight' => $weight++, ]); $food_amounts[$key]->food()->associate($food_id); } $recipe->foodAmounts()->saveMany($food_amounts); $steps = []; $number = 1; // TODO: Handle removals. foreach (array_filter($input['steps']) as $key => $step) { $steps[$key] = $recipe->steps[$key] ?? new RecipeStep(); $steps[$key]->fill(['number' => $number++, 'step' => $step]); } $recipe->foodAmounts()->saveMany($steps); }); } catch (\Exception $e) { DB::rollBack(); return back()->withInput()->withErrors("Failed to updated recipe due to database error: {$e->getMessage()}."); } session()->flash('message', "Recipe {$recipe->name} updated!"); return redirect()->route('recipes.show', $recipe); } /** * Remove the specified resource from storage. * * @param \App\Models\Recipe $recipe * @return \Illuminate\Http\Response */ public function destroy(Recipe $recipe) { // } }