Replicating Database Records in Laravel
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.
The naive approach
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.
The solution
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.
A quick note on timestamps
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!