Eloquentオブジェクトを簡単に複製する方法はありますか(その関係すべてを含む)?
たとえば、これらのテーブルがある場合:
users ( id, name, email )
roles ( id, name )
user_roles ( user_id, role_id )
users
テーブルに新しい行を作成することに加えて、id
を除くすべての列が同じであることに加えて、user_roles
テーブルに新しい行を作成し、同じ役割を割り当てます。新しいユーザー。
このようなもの:
$user = User::find(1);
$new_user = $user->clone();
ユーザーモデルの場所
class User extends Eloquent {
public function roles() {
return $this->hasMany('Role', 'user_roles');
}
}
belongsToMany関係についてlaravel 4.2でテスト済み
モデルにいる場合:
//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);
}
Eloquentが提供する複製機能を試すこともできます:
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Model.html#method_replicate
$user = User::find(1);
$new_user = $user->replicate();
$new_user->Push();
これを試してみてください( オブジェクトの複製 ):
$user = User::find(1);
$new_user = clone $user;
clone
はディープコピーを行わないため、子オブジェクトが使用可能な場合、子オブジェクトはコピーされません。この場合、clone
を使用して子オブジェクトを手動でコピーする必要があります。例えば:
$user = User::with('role')->find(1);
$new_user = clone $user; // copy the $user
$new_user->role = clone $user->role; // copy the $user->role
あなたの場合、roles
はRole
オブジェクトのコレクションになるため、コレクション内の各Role object
はclone
を使用して手動でコピーする必要があります。
また、roles
を使用してwith
をロードしないと、それらがロードされないか、$user
で使用できなくなります。 '$user->roles
を呼び出すと、それらのオブジェクトは$user->roles
の呼び出し後の実行時にロードされ、これまでは、これらのroles
はロードされません。
この答えはLarave-4
に対するものでしたが、現在Laravelはreplicate()
メソッドを提供しています。たとえば:
$user = User::find(1);
$newUser = $user->replicate();
// ...
Laravelの場合5. hasMany関係でテスト済み。
$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());
}
}
以下に、@ sabrina-gelbartのソリューションの更新バージョンを示します。これは、彼女が投稿したとおり、belongsToManyの代わりに、すべてのhasMany関係を複製します。
//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();
}
}
次のコードを使用して$ userという名前のコレクションがある場合、すべてのリレーションを含む、古いコレクションと同一の新しいコレクションが作成されます。
$new_user = new \Illuminate\Database\Eloquent\Collection ( $user->all() );
このコードはlaravel 5用です。
これはlaravel 5.8にあり、古いバージョンでは試していません
//# this will clone $eloquent and asign all $eloquent->$withoutProperties = null
$cloned = $eloquent->cloneWithout(Array $withoutProperties)
編集、ちょうど今日2019年4月7日 laravel 5.8.10を開始
今すぐ複製を使用できます
$post = Post::find(1);
$newPost = $post->replicate();
$newPost->save();
必要なリレーションによってオブジェクトをフェッチし、その後複製すると、取得したすべてのリレーションも複製されます。例えば:
$oldUser = User::with('roles')->find(1);
$newUser = $oldUser->replicate();
他の解決策があなたをなだめない場合、これを行う別の方法は次のとおりです。
<?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);
}
トリックは、Laravelが新しいレコードを作成するように、id
およびexists
プロパティを消去することです。
自己関係の複製は少し注意が必要ですが、例を示しました。古いIDから新しいIDへのマッピングを作成してから、再同期するだけです。