[Laravel][Collection] 文字列の部分一致を抽出する小技

Laravel の Collection 、超便利なようで、ちょいちょいできないことがあるような感じがするのですが、
やりようによってはできたりもするという割と良い事例だなと思ったので整理して投稿します。

やりたかったこと

Collection中のとある key カラムの文字列値が、指定の val 文字列と部分一致している行の抽出。
SQLで言うと、WHERE key LIKE "%{target}%"のような感じ。

見つけた小技


$filtered = $records->filter(function ($record) use ($key, $val) {  
    return strpos($record[$key], $val) !== false;  
});  

説明

変数名 説明 備考
$records 抽出元のデータ群
filter Collectionクラスのメソッド Laravel docs,
Laravel API reference
$record ↑の単数形。「個々のレコード」という意味に相当
$key カラム名を入れる変数
$val これと一致しているところがあったら
抽出したい文字列を入れる変数
strpos PHPの関数 PHP manual(ja)
$record[$key] 格納されている値
|
$filtered 部分一致するレコードを抽出した結果
  • strposを使っているのがちょっとしたポイント。
    ここの関数(と判定)を変えることで、目的に応じて違った抽出もやれそう。

試した環境

  • PHP 7.3.10
  • Laravel 5.8.35

検証内容

tinker を利用

ここをクリックすると展開されます
# php artisan tinker  
Psy Shell v0.9.9 (PHP 7.3.10  cli) by Justin Hileman  
>>> $records = collect([  
...     ['id' => 1, 'phrase' => 'あいうえ'],  
...     ['id' => 2, 'phrase' => 'いうえお'],  
...     ['id' => 3, 'phrase' => 'うえおあ'],    //おあ includes  
...     ['id' => 4, 'phrase' => 'えおあい'],    //おあ includes  
...     ['id' => 5, 'phrase' => 'おあいう'],    //おあ includes  
... ]);  
=> Illuminate\Support\Collection {#3278  
     all: [  
       [  
         "id" => 1,  
         "phrase" => "あいうえ",  
       ],  
       [  
         "id" => 2,  
         "phrase" => "いうえお",  
       ],  
       [  
         "id" => 3,  
         "phrase" => "うえおあ",  
       ],  
       [  
         "id" => 4,  
         "phrase" => "えおあい",  
       ],  
       [  
         "id" => 5,  
         "phrase" => "おあいう",  
       ],  
     ],  
   }  
>>> $conditions = ['phrase' => 'おあ'];     //LIKE的な検索をしたい文字列  
>>> foreach ($conditions as $key => $val) {  
...     if (in_array($key, [  
...         'phrase',  
...     ])) {  
...         $filtered = $records->filter(function ($record) use ($key, $val) {  
...             return \strpos($record[$key], $val) !== false;  
...         });  
...         $records = $filtered;  
...     }  
... }  
>>> $filtered->all();  
=> [  
     2 => [  
       "id" => 3,  
       "phrase" => "うえおあ",  
     ],  
     3 => [  
       "id" => 4,  
       "phrase" => "えおあい",  
     ],  
     4 => [  
       "id" => 5,  
       "phrase" => "おあいう",  
     ],  
   ]  
>>>  

Appendix