Gibt es eine Möglichkeit, ein eloquentes Objekt einschließlich aller seiner Beziehungen einfach zu klonen?
Wenn ich zum Beispiel diese Tabellen hätte:
users ( id, name, email )
roles ( id, name )
user_roles ( user_id, role_id )
Zusätzlich zum Erstellen einer neuen Zeile in der users
Tabelle, mit Ausnahme aller Spalten id
, sollte auch eine neue Zeile in der user_roles
Tabelle erstellt werden, die dem neuen Benutzer dieselbe Rolle zuweist.
Etwas wie das:
$user = User::find(1);
$new_user = $user->clone();
Wo das Benutzermodell hat
class User extends Eloquent {
public function roles() {
return $this->hasMany('Role', 'user_roles');
}
}
Sie können auch die Replikationsfunktion von eloquent ausprobieren:
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Model.html#method_replicate
$user = User::find(1); $new_user = $user->replicate(); $new_user->push();
quelle
$user = User::with('roles')->find(1);
oder sie laden, nachdem Sie das Modell haben: Die ersten beiden Zeilen wären also$user = User::find(1); $user->load('roles');
replicate()
setzt die Relationen undpush()
rekursiv in die Relationen und speichert sie.$new_user->roles()->save($oldRole->replicate)
Sie können dies versuchen ( Objektklonen ):
$user = User::find(1); $new_user = clone $user;
Da
clone
nicht tief kopiert wird, werden untergeordnete Objekte nicht kopiert, wenn ein untergeordnetes Objekt verfügbar ist. In diesem Fall müssen Sie das untergeordnete Objektclone
manuell kopieren . Zum Beispiel:$user = User::with('role')->find(1); $new_user = clone $user; // copy the $user $new_user->role = clone $user->role; // copy the $user->role
In Ihrem Fall handelt
roles
es sich um eine Sammlung vonRole
Objekten, sodass jedes ObjektRole object
in der Sammlung manuell mit kopiert werden mussclone
.Außerdem müssen Sie sich dessen bewusst sein. Wenn Sie die
roles
Verwendung nicht laden ,with
werden diese nicht geladen oder sind im nicht verfügbar.$user
Wenn Sie aufrufen, werden$user->roles
diese Objekte zur Laufzeit nach diesem Aufruf geladen von$user->roles
und bis dahin werden dieseroles
nicht geladen.Aktualisieren:
Diese Antwort war für
Larave-4
und jetzt bietet Laravelreplicate()
Methode an, zum Beispiel:$user = User::find(1); $newUser = $user->replicate(); // ...
quelle
null
:-)Für Laravel 5. Getestet mit hasMany Beziehung.
$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()); } }
quelle
Hier ist eine aktualisierte Version der Lösung von @ sabrina-gelbart, die alle hasMany-Beziehungen klonen wird, anstatt nur die gehörenden ToMany, wie sie gepostet hat:
//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(); } }
quelle
some_parent_id
nicht für alle Beziehungen gleich ist. Dies ist jedoch nützlich, danke.Dies ist in Laravel 5.8, in älteren Versionen nicht ausprobiert
//# this will clone $eloquent and asign all $eloquent->$withoutProperties = null $cloned = $eloquent->cloneWithout(Array $withoutProperties)
bearbeiten, erst heute 7. April 2019 Laravel 5.8.10 gestartet
kann jetzt replizieren verwenden
$post = Post::find(1); $newPost = $post->replicate(); $newPost->save();
quelle
Wenn Sie eine Sammlung mit dem Namen $ user haben, die den folgenden Code verwendet, wird eine neue Sammlung erstellt, die mit der alten identisch ist, einschließlich aller Beziehungen:
$new_user = new \Illuminate\Database\Eloquent\Collection ( $user->all() );
Dieser Code ist für Laravel 5.
quelle
$new = $old->slice(0)
?Wenn Sie ein Objekt mit einer beliebigen Beziehung abrufen und anschließend replizieren, werden auch alle abgerufenen Beziehungen repliziert. zum Beispiel:
$oldUser = User::with('roles')->find(1); $newUser = $oldUser->replicate();
quelle
Hier ist ein Merkmal, das alle geladenen Beziehungen auf einem Objekt rekursiv dupliziert . Sie können dies leicht für andere Beziehungstypen wie Sabrinas Beispiel für Gehört zu Viele erweitern.
trait DuplicateRelations { public static function duplicateRelations($from, $to) { foreach ($from->relations as $relationName => $object){ if($object !== null) { if ($object instanceof Collection) { foreach ($object as $relation) { self::replication($relationName, $relation, $to); } } else { self::replication($relationName, $object, $to); } } } } private static function replication($name, $relation, $to) { $newRelation = $relation->replicate(); $to->{$name}()->create($newRelation->toArray()); if($relation->relations !== null) { self::duplicateRelations($relation, $to->{$name}); } } }
Verwendung:
//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.nested_relation'); // duplication all LOADED relations including nested. self::duplicateRelations($this, $new);
quelle
Hier ist eine andere Möglichkeit, dies zu tun, wenn die anderen Lösungen Sie nicht beruhigen:
<?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); }
Der Trick besteht darin, die Eigenschaften
id
und zuexists
löschen, damit Laravel einen neuen Datensatz erstellt.Das Klonen von Selbstbeziehungen ist etwas schwierig, aber ich habe ein Beispiel beigefügt. Sie müssen nur eine Zuordnung alter IDs zu neuen IDs erstellen und dann erneut synchronisieren.
quelle