【Laravel】fillを使って同じカラム名を持つ複数のモデルを更新する

プログラミング

「laravel fill」「laravel fill model」といったキーワードでこのページに訪問される方がいらっしゃいましたので、モデルの複数カラムを一気にセットする方法を下記に記事にしました。ご参考にしていただければ幸いです。

 Laravelでモデルの複数カラムを一気にセットしたいとき、fill()メソッドを使うと便利です。
入力フォームのname属性をカラム名と同じにしておくと、「$model->fill($request->all())」とするだけで一気にセットできます。
カラムの追加に伴うソースコードの変更が不要のため、大変便利です。

$form = $request->all() ;
/*
    array:6 (
        "name" => "おじさん2355"
        "generation" => "団塊ジュニア"
        "tel" => "00-0000-0000"
    )
*/

$user->fill($request->all());
/*  下記を一括でセットできる!
    'name' => $request->name,  
    'generation' => $request->generation,
    'tel' => $request->tel
*/

 しかし、ひとつの入力フォームを使って、同じカラム名を持つ複数のモデルを更新する場合、name属性とカラム名を同じにすることができません。

 下記の例では、カラム名「name」がuserモデルとpetモデルの両方にあるため、入力フォームのname属性をカラム名と同じにすることができません。

$form = $request->all() ;
/*
    array:6 (
        "user_name" => "おじさん2355"
        "generation" => "団塊ジュニア"
        "tel" => "00-0000-0000"
        "pet_name" => "モモ"
        "category" => "bird"
        "age" => 1
    )
*/

$user->fill([
    'name' => $request->user_name, // $user、$pet で「name」が共通 
    'generation' => $request->generation,
    'tel' => $request->tel
]);

$pet->fill([
    'name' => $request->pet_name, // $user、$pet で「name」が共通
    'category' => $request->category,
    'age' => $request->age
]);

 カラム追加時にソースコードを変更しなくて済む、いい方法はないものでしょうか?

 ありました!!

 具体的には、以下のように_filter()関数を作成します。

form = $request->all() ;
/*
    array:6 (
        "user_name" => "おじさん2355"
        "user_generation" => "団塊ジュニア"
        "user_tel" => "00-0000-0000"
        "pet_name" => "モモ"
        "pet_category" => "bird"
        "pet_age" => 1
    )
*/

$user->fill(_filter($request->all(),'/^user_(.+)/'));
/*
    array:3 (
        "name" => "おじさん2355"
        "generation" => "団塊ジュニア"
        "tel" => "00-0000-0000"
    )
*/

$pet->fill(_filter($request->all(),'/^pet_(.+)/'));
/*
    array:6 (
        "name" => "モモ"
        "category" => "bird"
        "age" => 1
    )
*/
public function _filter($arr , $pattern)
{
    $p = array_intersect_key(
        $arr , 
        array_flip(
            preg_grep(
                $pattern, 
                array_keys($arr)
            )
        )
    );

    return array_combine(
        preg_replace($pattern,'$1',$array_keys($p)) , 
        array_values($p)
    );
}
  • 入力フォームのname属性は「モデル名_カラム名」にする。
  • fill()メソッドで値をセットする前に、セットするモデル名のフォームデータを抜き出す。
  • 抜き出したフォームデータのキーワードから「モデル名_」を削除する。
おじさん
おじさん

入力フォームのname属性に、モデル名を記載しておくのがポイントです。

_filter()関数でどのようなことをしているのか、$userモデルへのデータセットを例に、順を追って解説します。

スポンサーリンク

フォームデータからキーワードを取り出す

 array_keys()を使って、フォームデータの配列からキーワードの一覧を取得します。

$param1 = $request->all();
/*
    array:6 (
        "user_name" => "おじさん2355"
        "user_generation" => "団塊ジュニア"
        "user_tel" => "00-0000-0000"
        "pet_name" => "モモ"
        "pet_category" => "bird"
        "pet_age" => 1
    )
*/

$param2 = array_keys($param1);
/*
    array:6 (
        1 => "user_name"
        2 => "user_generation"
        3 => "user_tel"
        4 => "pet_name"
        5 => "pet_category"
        6 => "pet_age"
    )
*/

必要なモデルのキーワードを抜き出す

  preg_grep()を使って、「user_」から始まるキーワードを抜き出します。

$param3 = preg_grep('/^user_(.+)/', $param2) ;
/*
    array:3 (
        1 => "user_name"
        2 => "user_generation"
        3 => "user_tel"
    )
*/

必要なフォームデータを抜き出す

  array_intersect_key()とarray_flip()を利用して、フォームデータの絞り込みを行います。

$param4 = array_intersect_key($param1 , array_flip($param3));
/*
    array:3 (
        "user_name" => "おじさん2355"
        "user_generation" => "団塊ジュニア"
        "user_tel" => "00-0000-0000"
    )
*/

モデル名を削除したキーワードの一覧を作成する

絞り込んだフォームデータからarray_keys()でキーワードを抜き出し、preg_replace()でキーワード名を置換します。

$param5 = preg_replace('/^user_(.+)/','$1',$array_keys($param4));
/*
    array:3 (
        1 => "name"
        2 => "generation"
        3 => "tel"
    )
*/

フォームデータから値の一覧を作成する

 array_values()を使用して値を抜き出します。

$param6 = array_values($param4);
/*
    array:3 (
        1 => "おじさん2355"
        2 => "団塊ジュニア"
        3 => "00-0000-0000"
    )
*/

返り値を作成する

 array_combine()によってキーワード一覧と値の一覧同士を結合します。

$param7 = array_combine($param5 , $param6)
/*
    array:3 (
        "name" => "おじさん2355"
        "generation" => "団塊ジュニア"
        "tel" => "00-0000-0000"
    )
*/

まとめ

 入力フォームのname属性の工夫が必要ですが、ソースコードにカラム名を記載しなくて済みます。

参考になればうれしいです。

参考

タイトルとURLをコピーしました