I recently found myself needing to replicate a database record in Laravel. Turns out, there's a really easy way to achieve this.
First, let's take a look at a naive way we might replicate a record.
Imagine we had a Visit
model for analytics that contained some json
data about the visit.
Visit::create(['data' => ['ip' => '127.0.0.1']]);
One method of replicating it might be the following.
$visit = Visit::find(1);
$replicateVisit = Visit::create($visit->getAttributes());
This does replicate the record in the database, but with a nasty side effect. The data
column is actually cast to json
.
protected $casts = [
'data' => 'json'
];
This means the replicate data
property ends up escaped when inserting back into the replicated record.
"{\"ip\":\"127.0.0.1\"}" // what we get with the method above
{"ip":"127.0.0.1"} // what we need
No doubt there's a way around this, but we're not even going to explore it.
What you came for.
Here's how we replicate a record nicely in the database, without any side effects.
$visit = Visit::find(1);
$visit->replicate()->save();
Notice the save
call. That's because the replicate
method just replicates the existing model and doesn't persist it.
The benefit to having to explicitly save
a record is we can modify parts of the replicated record before it goes back into the database.
$replicated = $visit->replicate();
$replicated['data->ip'] = 'localhost';
$replicated->save();
The data->ip
array access is just because we're working with json
data here. For normal database columns, you'd just access them as a property.
$replicated = $visit->replicate();
$replicated->verified = true;
$replicated->save();
Easy and clean.
When you replicate a record, the created_at
and updated_at
timestamps will represent the date/time that the new record was created. Those columns are excluded from the replication.
Of course, if you wanted to match those for any reason, you'd do something like this.
$visit = Visit::find(1);
$replicated = $visit->replicate();
$replicated->created_at = $visit->created_at;
$replicated->updated_at = $visit->updated_at;
$replicated->save();
Happy replicating!