it-swarm.com.de

Ein eloquentes Objekt einschließlich aller Beziehungen klonen?

Gibt es eine Möglichkeit, ein eloquentes Objekt einschließlich aller seiner Beziehungen leicht zu klonen?

Wenn ich beispielsweise diese Tabellen hätte:

users ( id, name, email )
roles ( id, name )
user_roles ( user_id, role_id )

Neben dem Erstellen einer neuen Zeile in der Tabelle users, wobei alle Spalten mit Ausnahme von id identisch sind, sollte auch eine neue Zeile in der Tabelle user_roles erstellt werden, die dem neuen Benutzer dieselbe Rolle zuweist.

Etwas wie das:

$user = User::find(1);
$new_user = $user->clone();

Wo hat das Benutzermodell

class User extends Eloquent {
    public function roles() {
        return $this->hasMany('Role', 'user_roles');
    }
}
50
andrewtweber

getestet in laravel 4.2 für die Verbindungen von ehemann-zu-mehreren

wenn Sie im Modell sind:

    //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);
    }
35
Sabrina Leggett

Sie können auch die Replikat-Funktion 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();
50
Piotr Borek

Sie können dies versuchen ( Object Cloning ):

$user = User::find(1);
$new_user = clone $user;

Da clone nicht tiefkopiert wird, werden untergeordnete Objekte nicht kopiert, wenn ein untergeordnetes Objekt verfügbar ist. In diesem Fall müssen Sie das untergeordnete Objekt manuell mit clone 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 ist roles eine Sammlung von Role-Objekten, sodass jeder Role object in der Sammlung manuell mit clone kopiert werden muss.

Wenn Sie die roles nicht mit with laden, werden diese nicht geladen oder sind nicht in $user verfügbar. Wenn Sie $user->roles aufrufen, werden diese Objekte beim Ausführen geladen Zeit nach diesem Aufruf von $user->roles und bis zu diesem Zeitpunkt werden diese roles nicht geladen.

Aktualisieren:

Diese Antwort war für Larave-4 und jetzt bietet Laravel replicate() Methode an, zum Beispiel:

$user = User::find(1);
$newUser = $user->replicate();
// ...
21
The Alpha

Für Laravel 5. Mit hasMany Relation getestet.

$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());
    }
}
11
JIM

Hier ist eine aktualisierte Version der Lösung von @ sabrina-gelbart, mit der alle hasMany-Beziehungen geklont werden, statt nur die likesToMany, wie sie geschrieben 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();
        }
    }
6
davidethell

Wenn Sie über eine Sammlung namens $ user verfügen, wird mithilfe des nachstehenden Codes 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 gilt für Laravel 5.

3
Mihai Crăiță

Wenn Sie ein Objekt mit einer beliebigen Beziehung abrufen und anschließend replizieren, werden alle von Ihnen abgerufenen Beziehungen ebenfalls repliziert. zum Beispiel:

$oldUser = User::with('roles')->find(1);
$newUser = $oldUser->replicate();
1
elyas.m

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

$post = Post::find(1);
$newPost = $post->replicate();
$newPost->save();
0
david valentino

Hier ist eine andere Möglichkeit, wenn die anderen Lösungen Sie nicht befriedigen:

<?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 exists zu löschen, damit Laravel einen neuen Datensatz erstellt.

Das Klonen von Selbstbeziehungen ist ein bisschen schwierig, aber ich habe ein Beispiel beigefügt. Sie müssen lediglich eine Zuordnung alter IDs zu neuen IDs erstellen und dann erneut synchronisieren.

0
mpen