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:
<?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:
<?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:
<?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:
<?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:
<?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:
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):
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:
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:
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
- Replicating Models (Laravel Documentation)
- Artisan Tinker (Laravel Documentation)
Using `push()` method instead of `save()` method when cloning with relationships confuses me. Can you elaborate?