duplicate - laravel eloquent
¿Clonar un objeto elocuente incluyendo todas las relaciones? (7)
Aquí hay otra forma de hacerlo si las otras soluciones no lo apaciguan:
<?php
/** @var /App/Models/Booking $booking */
$booking = Booking::query()->with(''segments.stops'',''billingItems'',''invoiceItems.applyTo'')->findOrFail($id);
$booking->id = null;
$booking->exists = false;
$booking->number = null;
$booking->confirmed_date_utc = null;
$booking->save();
$now = CarbonDate::now($booking->company->timezone);
foreach($booking->segments as $seg) {
$seg->id = null;
$seg->exists = false;
$seg->booking_id = $booking->id;
$seg->save();
foreach($seg->stops as $stop) {
$stop->id = null;
$stop->exists = false;
$stop->segment_id = $seg->id;
$stop->save();
}
}
foreach($booking->billingItems as $bi) {
$bi->id = null;
$bi->exists = false;
$bi->booking_id = $booking->id;
$bi->save();
}
$iiMap = [];
foreach($booking->invoiceItems as $ii) {
$oldId = $ii->id;
$ii->id = null;
$ii->exists = false;
$ii->booking_id = $booking->id;
$ii->save();
$iiMap[$oldId] = $ii->id;
}
foreach($booking->invoiceItems as $ii) {
$newIds = [];
foreach($ii->applyTo as $at) {
$newIds[] = $iiMap[$at->id];
}
$ii->applyTo()->sync($newIds);
}
El truco es borrar el id
y las propiedades exists
para que Laravel cree un nuevo registro.
Clonar las relaciones personales es un poco complicado, pero he incluido un ejemplo. Solo tiene que crear una asignación de identificadores antiguos a nuevos identificadores y luego volver a sincronizar.
¿Hay alguna forma de clonar fácilmente un objeto elocuente, incluidas todas sus relaciones?
Por ejemplo, si tuviera estas tablas:
users ( id, name, email )
roles ( id, name )
user_roles ( user_id, role_id )
Además de crear una nueva fila en la tabla de users
, con todas las columnas iguales excepto id
, también debe crear una nueva fila en la tabla user_roles
, asignando el mismo rol al nuevo usuario.
Algo como esto:
$user = User::find(1);
$new_user = $user->clone();
Donde el modelo de Usuario tiene
class User extends Eloquent {
public function roles() {
return $this->hasMany(''Role'', ''user_roles'');
}
}
Aquí hay una versión actualizada de la solución de @ sabrina-gelbart que clonará todas las relaciones de Many en lugar de solo belongsToMany como publicó:
//copy attributes from original model
$newRecord = $original->replicate();
// Reset any fields needed to connect to another parent, etc
$newRecord->some_id = $otherParent->id;
//save model before you recreate relations (so it has an id)
$newRecord->push();
//reset relations on EXISTING MODEL (this way you can control which ones will be loaded
$original->relations = [];
//load relations on EXISTING MODEL
$original->load(''somerelationship'', ''anotherrelationship'');
//re-sync the child relationships
$relations = $original->getRelations();
foreach ($relations as $relation) {
foreach ($relation as $relationRecord) {
$newRelationship = $relationRecord->replicate();
$newRelationship->some_parent_id = $newRecord->id;
$newRelationship->push();
}
}
Para Laravel 5. Probado con hasMany relation.
$model = User::find($id);
$model->load(''invoices'');
$newModel = $model->replicate();
$newModel->push();
foreach($model->getRelations() as $relation => $items){
foreach($items as $item){
unset($item->id);
$newModel->{$relation}()->create($item->toArray());
}
}
Puede intentar esto ( clonación de objetos ):
$user = User::find(1);
$new_user = clone $user;
Dado que el clone
no copia profundamente, los objetos secundarios no se copiarán si hay algún objeto hijo disponible y en este caso deberá copiar el objeto secundario utilizando clone
manualmente. Por ejemplo:
$user = User::with(''role'')->find(1);
$new_user = clone $user; // copy the $user
$new_user->role = clone $user->role; // copy the $user->role
En su caso, los roles
serán una colección de objetos Role
, por lo que cada Role object
en la colección debe copiarse manualmente utilizando clone
.
Además, debe tener en cuenta que, si no carga los roles
usan with
entonces esos no estarán cargados o no estarán disponibles en el $user
y cuando llame a $user->roles
entonces esos objetos se cargará en el tiempo de ejecución después de esa llamada de $user->roles
y hasta esto, esos roles
no se cargan.
Actualizar:
Esta respuesta fue para Larave-4
y ahora Laravel ofrece el método replicate()
, por ejemplo:
$user = User::find(1);
$newUser = $user->replicate();
// ...
Si tiene una colección llamada $ user, utilizando el código de abajo, crea una nueva colección idéntica a la anterior, incluidas todas las relaciones:
$new_user = new /Illuminate/Database/Eloquent/Collection ( $user->all() );
este código es para laravel 5.
También puede probar la función de réplica proporcionada por elocuente:
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Model.html#method_replicate
$user = User::find(1);
$new_user = $user->replicate();
$new_user->push();
probado en laravel 4.2 para las relaciones de belongsToMany
si estás en el modelo:
//copy attributes
$new = $this->replicate();
//save model before you recreate relations (so it has an id)
$new->push();
//reset relations on EXISTING MODEL (this way you can control which ones will be loaded
$this->relations = [];
//load relations on EXISTING MODEL
$this->load(''relation1'',''relation2'');
//re-sync everything
foreach ($this->relations as $relationName => $values){
$new->{$relationName}()->sync($values);
}