いつの間にか追加されていた sole()
この間 sole()
メソッドでひと悶着あったので、使い方を調べておく。
sole()
soleメソッドは、指定した真偽テストをパスしたアイテムが正確に1つだけの場合、コレクション内の最初の要素を返します。
だそうで。
要するに、Eloquentで検索をかけたとき、要素が1つだけのときは first()
の挙動、
それ以外の時は例外を吐く面白い関数。
※ ちなみに Eloquent と Collection で使用可能
> collect([1, 2, 3])->sole()
Illuminate\Support\MultipleItemsFoundException 3 items were found.
> collect([1])->sole()
= 1
> collect([])->sole()
Illuminate\Support\ItemNotFoundException
面倒な点がこやつ、例外を吐いてくるんですよ!
それを知らなかったので、偶然複製されたデータに無限に引っ掛かっていた...
どの用途で使うのが良いのだろうか...
正直、count()
first()
でハンドリングしたほうが綺麗に書けるのではないか?
これを使わなければ!という場面が思いつかない...
ネットで調べても、soleの紹介のみで使い方の議論が無いのだが!
まぁ確実に1つしかないことを保証できるので、不用意な処理は防げそう...
ソース
ここで終わっても面白くないので、実装を見に行く。
実装、二つで違うんだ...
Eloquent
https://github.com/laravel/framework/blob/11.x/src/Illuminate/Database/Eloquent/Builder.php#L673
これは内部で BuidsQueries.php
の trait を呼んでる。
本体がこいつ
public function sole($columns = ['*'])
{
$result = $this->take(2)->get($columns);
$count = $result->count();
if ($count === 0) {
throw new RecordsNotFoundException;
}
if ($count > 1) {
throw new MultipleRecordsFoundException($count);
}
return $result->first();
}
ははーん、いつものマクロみたいな実装なのね。
Collection
https://github.com/laravel/framework/blob/11.x/src/Illuminate/Collections/Collection.php#L1373
public function sole($key = null, $operator = null, $value = null)
{
$filter = func_num_args() > 1
? $this->operatorForWhere(...func_get_args())
: $key;
$items = $this->unless($filter == null)->filter($filter);
$count = $items->count();
if ($count === 0) {
throw new ItemNotFoundException;
}
if ($count > 1) {
throw new MultipleItemsFoundException($count);
}
return $items->first();
}
あーフィルターって、unless + filter で実現してるんだ。
こちらもマクロ的いつもの実装。
まとめ
Laravel はソースコードまで全部読めるので、気になったら読みに行くと良い。
めっちゃ勉強になる、というかコアの思想を理解しないときちゃない実装になりがち。
Laravel API 読もう!