BLOG

ブログ

2024/04/22 プログラミング技術系

【Laravel】replicateで既存データを複製する

この記事を書いた人 T.S

初めに

Laravelのreplicateメソッドを使用して、既存のDBデータを複製する方法をご紹介します。

単純にデータを丸ごと複製する方法の他に、データを一部調整して複製したい場合や、リレーション先のデータも複製したい場合の方法も載せています。複製機能を実装したい方、replicateメソッドに興味がある方の参考になれば幸いです🙌

参考:Laravel 9.x Eloquentの準備 モデルの複製

検証環境は以下の通りです。

  • Laravel:9.38.0
  • PHP:8.0.25
  • MySQL:8.0.29

データの複製(データを丸々複製したい場合)

// 複製元を取得
$shopData = Shop::find(1);

// 複製
$newShopData = $shopData->replicate();
$newShopData->save();

ここでは、replicate()で複製準備をし、save()で実際にデータを登録しています。
今回のような基本的な書き方の場合(replicate() → save())では、下記3カラム以外の全てのカラムデータをそのまま複製することができます。
下記3カラムについては、いずれも自動的に値がセットされるので特に指定しなくても大丈夫です🙆‍♂️

  • id(primary_key):自動採番
  • created_at:自動セット(複製処理時の日時)
  • updated_at:自動セット(複製処理時の日時)

データの複製(データの一部を変更して複製したい場合)

// 複製元を取得
$shopData = Shop::find(1);

// 複製
$newShopData = $shopData->replicate();
$newShopData->is_new_open = true;
$newShopData->save();

複製対象にユニーク属性が設定されているカラムデータがある場合や、データの一部だけ書き換えて複製したい場合は、この書き方をします。
上記のようにreplicate()後に「カラム名」と「変更後の値」を指定することで、指定したカラムだけデータを書き換えることができます(指定していないカラムに関しては、元のデータのまま複製されます!)

リレーション先データも含めたデータの複製

単一テーブルだけでなく、紐づいたデータも一緒に複製することが可能です。

例として、店舗のテーブル(shops)と、商品のテーブル(items)があり、店舗データ1件に対して、商品データが複数登録可能な「hasMany」と「belongsTo」の関係にあるとします。
(1対多のリレーションについて詳しく知りたい方は、弊社メンバーのこちらの記事がオススメです!)

今回は、店舗データ&紐づく商品データを、まとめて複製してみます。

// 複製元を取得(リレーションデータ付き)
$shopData = Shop::with('items')->find(1);

// 複製
$newShopData = $shopData->replicate();
$newShopData->save();

// 複製元データのリレーションデータを複製
$shopData->items->each(function ($item) use ($newShopData) {
    $newItem = $item->replicate();
    $newItem->shop_id = $newShopData->id; // 外部キーに複製後のidを指定
    $newItem->save();
})

ここでのポイントは、リレーションデータ(itemsデータ)の外部キーに、複製後のshop.idデータを指定したところです!
リレーションデータの外部キー(ここではitemsテーブルのshop_id)に対して指定がない場合は、複製前(複製元)のデータを参照したままとなるので注意が必要です💡

ちなみにリレーションデータにアクセスする際(今回の例では$shopData->itemsの部分)、モデルデータの取得時にwithでリレーション先データを指定しておくと、Eagerロードとなり、N+1問題の回避・パフォーマンスの向上に繋がるためオススメです。

余談

// この場合の$newShopDataにはbool値が入る(成功したらtrue, 失敗したらfalse)
$newShopData = $shopData->replicate()->save();

// この場合の$newShopDataには複製したモデルデータが入る
$newShopData = $shopData->replicate();
$newShopData->save();

複製処理について、上記どちらの書き方でも同じように動きはするのですが、変数に格納されるデータが異なるため注意が必要です。

replicate()->save()を一行にまとめて書いた場合は、save処理の成否データのみしか取得できないため、処理後に$newShopData->idなどで複製後のデータを参照することができません。複製後のデータを参照しない・使わないという場合は問題ないかもしれませんが、なるべく複数行に分けて書く方が、後の拡張性も高まるので良いかな〜、、と個人的には思いました。

終わりに

今回は、Laravelのreplicateメソッドを用いて、既存のDBデータを複製する方法についてご紹介しました。

replicateメソッドは、基本的な複製機能自体を数行で実装できる点や、ここはこのデータを指定したい!という調整が簡単という点で、便利で扱いやすいメソッドだと思います!
私自身、replicateメソッドの存在を知る前までは、データの複製機能を作るには、複製元のデータを1つ1つ指定してcreatesaveあたりでどうにかするしかない…と思っていたので、こんなに便利なメソッドがあると知れて嬉しかったです😂
Laravelには”知らなかったけど便利な機能”がまだまだあるはずなので、今後もさまざまな機能に触れて、よりスマートな実装ができるよう精進したいです。



株式会社ウイングドアは福岡のシステム開発会社です。
現在、私達と一緒に"楽しく仕事が出来る仲間"として、新卒・中途採用を絶賛募集しています!
ウイングドアの仲間達となら楽しく仕事できるかも?と興味をもった方、
お気軽にお問い合わせ下さい!

アーカイブ