0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【laravel】soleとかいうじゃじゃ馬

Posted at

いつの間にか追加されていた 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 を呼んでる。
本体がこいつ

https://github.com/laravel/framework/blob/11.x/src/Illuminate/Database/Concerns/BuildsQueries.php#L355

    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 読もう!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?