diff --git a/app/Http/Controllers/RecipeController.php b/app/Http/Controllers/RecipeController.php
index af0b77b..fad38fe 100644
--- a/app/Http/Controllers/RecipeController.php
+++ b/app/Http/Controllers/RecipeController.php
@@ -12,6 +12,7 @@ use App\Support\Number;
use App\Support\Nutrients;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
@@ -350,6 +351,30 @@ class RecipeController extends Controller
$recipe->ingredientSeparators()->saveMany($ingredient_separators);
}
+ /**
+ * Confirm duplicating recipe.
+ */
+ public function duplicateConfirm(Recipe $recipe): View {
+ return view('recipes.duplicate')->with('recipe', $recipe);
+ }
+
+ /**
+ * Duplicate a recipe.
+ */
+ public function duplicate(Request $request, Recipe $recipe): RedirectResponse
+ {
+ $attributes = $request->validate(['name' => ['required', 'string']]);
+
+ try {
+ $new_recipe = $recipe->duplicate($attributes);
+ } catch (\Throwable $e) {
+ return back()->withInput()->withErrors($e->getMessage());
+ }
+
+ return redirect()->route('recipes.show', $new_recipe)
+ ->with('message', "Recipe {$recipe->name} duplicated!");
+ }
+
/**
* Confirm removal of specified resource.
*/
diff --git a/app/Models/Recipe.php b/app/Models/Recipe.php
index e4d5600..d8a15bd 100644
--- a/app/Models/Recipe.php
+++ b/app/Models/Recipe.php
@@ -14,6 +14,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\DB;
use Spatie\Image\Manipulations;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
@@ -262,4 +263,55 @@ final class Recipe extends Model implements HasMedia
->optimize();
}
+ /**
+ * Duplicates the recipe, updating provided attributes.
+ *
+ * @throws \Throwable
+ */
+ public function duplicate(array $attributes): Recipe {
+ /** @var \App\Models\Recipe $recipe */
+ $recipe = $this->replicate();
+ $recipe->fill($attributes);
+
+ try {
+ DB::transaction(function () use ($recipe) {
+ $recipe->save();
+
+ $recipe->tags()->attach($this->tags);
+
+ $ingredient_amounts = [];
+ foreach ($this->ingredientAmounts as $ia) {
+ $new_ia = $ia->replicate();
+ $new_ia->parent_id = $recipe->id;
+ $new_ia->parent_type = Recipe::class;
+ $ingredient_amounts[] = $new_ia;
+ }
+ $recipe->ingredientAmounts()->saveMany($ingredient_amounts);
+
+ $steps = [];
+ foreach ($this->steps as $step) {
+ $new_step = $step->replicate();
+ $new_step->recipe_id = $recipe->id;
+ $steps[] = $new_step;
+ }
+ $recipe->steps()->saveMany($steps);
+
+ $separators = [];
+ foreach ($this->separators as $separator) {
+ $new_separator = $separator->replicate();
+ $new_separator->recipe_id = $recipe->id;
+ $separators[] = $new_separator;
+ }
+ $recipe->separators()->saveMany($separators);
+
+ $recipe->push();
+ });
+ } catch (\Throwable $e) {
+ DB::rollBack();
+ throw $e;
+ }
+
+ return $recipe;
+ }
+
}
diff --git a/resources/views/recipes/duplicate.blade.php b/resources/views/recipes/duplicate.blade.php
new file mode 100644
index 0000000..f891804
--- /dev/null
+++ b/resources/views/recipes/duplicate.blade.php
@@ -0,0 +1,30 @@
+
+ Duplicate {{ $recipe->name }}
+
+
+ Duplicate {{ $recipe->name }}?
+
+
+
+
diff --git a/resources/views/recipes/show.blade.php b/resources/views/recipes/show.blade.php
index 6642ca7..ddfe6c7 100644
--- a/resources/views/recipes/show.blade.php
+++ b/resources/views/recipes/show.blade.php
@@ -167,6 +167,9 @@
Edit Recipe
+
+ Duplicate Recipe
+
Delete Recipe
diff --git a/routes/auth.php b/routes/auth.php
index 3ad7c89..5e4f7c9 100644
--- a/routes/auth.php
+++ b/routes/auth.php
@@ -49,6 +49,9 @@ Route::middleware(['auth'])->group(function () {
// Recipes.
Route::resource('recipes', RecipeController::class);
Route::get('/recipes/{recipe}/delete', [RecipeController::class, 'delete'])->name('recipes.delete');
+ Route::get('/recipes/{recipe}/duplicate', [RecipeController::class, 'duplicateConfirm'])->name('recipes.duplicate.confirm');
+ Route::post('/recipes/{recipe}/duplicate', [RecipeController::class, 'duplicate'])->name('recipes.duplicate');
+
// Users.
Route::get('/profile/{user}', [ProfileController::class, 'show'])->name('profiles.show');