Laravel replicate including relationships but maintain original timestamps

Viewed 751

I am trying to replicate a record and its relationships in Laravel 8. But I want to keep the original records timestamps. I am able to do this on the main record, but the timestamps on all the relationships get set to the datetime that the record is replicated. I also have some observers set up and I dont want them firing when the replication takes place.

$order = App\Models\Order::with('comments', 'tracking_details')->find(4096);


$clone = $order->replicate()->fill([
    'tracking_number' => null,
    'created_at' => $order->created_at,
    'updated_at' => $order->updated_at,
]);

$clone->saveQuietly();


foreach ($order->comments as $comment) {
    App\Models\Comments::withoutEvents(function() use ($clone, $comment) {
        $clone->comments()->create($comment->toArray());
    });
}


foreach ($order->tracking_details as $details) {
    App\Models\TrackingDetails::withoutEvents(function() use ($clone, $details) {
        $clone->tracking_details()->create($details->toArray());
    });
}

Any help would be greatly appreciated.

4 Answers

For relationships, you can use query builder instead.

// main record

$order = Order::find(4096);

$clone = $order->replicate()->fill([
    'tracking_number' => null,
    'created_at' => $order->created_at,
    'updated_at' => $order->updated_at
]);

$clone->saveQuietly();

// comments relationship

$comments = Comments::toBase()->where('order_id', $order->id)->orderBy('id')->get()->map(function ($item) use ($clone) {
    unset($item->id);

    $item->order_id = $clone->id;

    return (array) $item;
});

Comments::insert($comments->toArray());

// tracking_details relationship

$trackingDetails = TrackingDetails::toBase()->where('order_id', $order->id)->orderBy('id')->get()->map(function ($item) use ($clone) {
    unset($item->id);

    $item->order_id = $clone->id;

    return (array) $item;
});

TrackingDetails::insert($trackingDetails->toArray());

In this case you don't work with eloquent, which means that no events will be fired and you will keep the original records timestamps.

Not sure if this will work, but have you tried disabling timestamps in your model?

public $timestamps = FALSE;

If you want your models to be able to save your timestamps via create() method, you should add created_at and updated_at properties to $fillable on your models. Reference: Making properties mass assignable

The created_at and updated_at columns are default timestamps which Laravel provides out of the box, create a cloned_at column default to null in the database and in your database model, add it to a fillable property, then you can simple insert data in the database where created_at and updated_at values will be parsed as a comma separated value, when retrieving the data, you can split and modify the string from CSV and parse it as a Carbon format, it's a dirty but a possible solution.

Related