How to Clone a Model in Laravel (With or Without Relations)

Cloning a model in Laravel can be a valuable feature for end users who want to save time by avoiding manual data entry. Fortunately Laravel Eloquent has the means to duplicate existing records built-in.

Cloning a Laravel Eloquent Model is achieved with $clone = $originalModel->replicate(). However, note that this doesn’t extend to relationships. To clone related data, apply a foreach loop to replicate related items and associate them with the clone.

This guide will show you how to clone eloquent models, both with and without their associated relationship data. I’ll also include a practical example of cloning a “Project” and “Task” model.

Let’s dive in!

Step 1: Create the Migrations

First, create the migration files for the projects and tasks tables by running the following Artisan commands:

php artisan make:migration create_projects_table --create=projects
php artisan make:migration create_tasks_table --create=tasks

Modify the migration files as follows:

For the projects table migration:

database/migrations/2023_08_06_163642_create_projects_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('projects', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            // Add any other columns you need for your project
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('projects');
    }
};

For the projects table migration use:

database/migrations/2023_08_06_163642_create_projects_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('projects', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            // Add any other columns you need for your project
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('projects');
    }
};

For the tasks table migration use:

database/migrations/2023_08_06_163643_create_tasks_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('tasks', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('project_id');
            $table->string('name');
            // Add any other columns you need for your task
            $table->timestamps();

            $table->foreign('project_id')
                  ->references('id')
                  ->on('projects')
                  ->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('tasks');
    }
};

Run the migration using the following command:

php artisan migrate

Step 2: Create the Models

Create the models for Project and Task by running the following Artisan command:

php artisan make:model Project -m
php artisan make:model Task -m

For the Project model, use the following code:

app/Models/Project.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Project extends Model
{
    protected $fillable = ['title'];

    public function tasks()
    {
        return $this->hasMany(Task::class);
    }
}

For the Task model, use the following code:

app/Models/Task.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    protected $fillable = ['project_id', 'title'];

    public function project()
    {
        return $this->belongsTo(Project::class);
    }
}

Step 3: Adding Some Test Data

We will now use Laravel Tinker to add some data which we can use to test the cloning later on. Laravel Tinker is an interactive shell for Laravel that allows you to interact with your application’s code and data.

To start Laravel Tinker run the following command:

php artisan tinker

In the Laravel Tinker prompt you can now copy/paste the following code:

use App\Models\Project;
use App\Models\Task;

// Create Projects
$project1 = Project::create(['title' => 'Project A']);
$project2 = Project::create(['title' => 'Project B']);

// Create Tasks for Project A
Task::create(['project_id' => $project1->id, 'title' => 'Task 1 for Project A']);
Task::create(['project_id' => $project1->id, 'title' => 'Task 2 for Project A']);

// Create Tasks for Project B
Task::create(['project_id' => $project2->id, 'title' => 'Task 1 for Project B']);
Task::create(['project_id' => $project2->id, 'title' => 'Task 2 for Project B']);

You should now see the following data in your database:

Screenshot Showing the Records in the tables tasks and projects After Testdata Creation

Step 4: Clone a Model Without Relations

To clone a model without its relations, you can use the replicate() method provided by Eloquent. Consider the following example code which clones a project:

$originalProject = Project::find(1);
$newProject = $originalProject->replicate();
$newProject->save();

After running and checking we can confirm the project with ID is duplicated (but its tasks are not):

Screenshot Showing the Records in the tables tasks and projects after Cloning a Project

Step 5: Clone a Model With Relations

Laravel’s built-in replicate() method doesn’t automatically clone a model’s relations. To replicate the relations of a model, you need to iterate through the related models using a foreach loop, invoking replicate() on each and then adding the result to the relevant relationship.

To streamline this process, you can add a custom method in your model. Here’s an example which handles cloning a project along with its associated tasks:

app/Models/Project.php
class Project extends Model
{
    // Other Project functions

    public function cloneWithTasks()
    {
        $clone = $this->replicate();
        $clone->push();

        // Clone related tasks
        foreach ($this->tasks as $task) {
            $clonedTask = $task->replicate();
            $clone->tasks()->save($clonedTask);
        }

        return $clone;
    }
}

Now we can easily run the following code to clone a project with its related tasks:

use App\Models\Project;
$originalProject = Project::find(1);
$clone = $originalProject->cloneWithTasks();

When we check the database we can confirm our newly created clone actually has cloned tasks assigned to it as well:

Screenshot Showing the tasks and projects Tables After Cloning a Project With its Related Task items

Conclusion

By following the steps outlined in this guide, you can easily clone models with or without their relations. This allows you to implement useful features like a clone button for your users, helping to minimize repetitive data entry tasks. Happy coding!

References

Johan van den Broek

Johan is the creator of laracoding.com. As a child, he began tinkering with various programming languages, many of which have been long forgotten today. Currently, he works exclusively with PHP and Laravel, and his passion for programming remains to this day.

One thought on “How to Clone a Model in Laravel (With or Without Relations)

  1. Using `push()` method instead of `save()` method when cloning with relationships confuses me. Can you elaborate?

Leave a Reply

Your email address will not be published. Required fields are marked *

Recent Posts