14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

この記事はLaravel Advent Calendar 2018 - Qiitaの22日目の記事です。

Laravel標準ORMであるEloquentとcollectionについて書きます。

  • Eloquent、collectionの2018年追加された機能のTips
  • Eloquent+collectionで実現する機能

#2018年追加された機能のTips

Laravel5.5.29以降

doesntExists()メソッドが追加されました

データ存在チェックで

if( !User::where('email', 'user@example.com')->exists() ){
}

と書いてたものが

if( User::where('email', 'user@example.com')->doesntExists()){
 }

と書けるようになりました。

withTrashed()メソッドに引数指定が追加されました

withTrashed()メソッドは論理削除したデータを取得データに含める場合に使用します。

今回の変更により、元々以下のようにフラグで切り分けて使っていたのを


public function index(Request $request)
{
    $query = User::query();

    if ($request->showDeleted) {
        $query->withTrashed();
    }

    return $query->get();
}

下記のようにwithTrashed()メソッドの引数に依存して使用する/しないを切り替える事が出来ます。

public function index(Request $request)
{
    return User::withTrashed($request->showDeleted)->get();
}

5.6以降

Model$castsを定義することで取得時指定したデータ形式にキャストされます。

protected $casts = [
    'birthday' => '誕生日:Y-m-d',
    'logined_at' => 'datetime:Y-m-d H:00',
];

orWhereDay()orWhereMonth()orWhereYear()が追加されました

\App\User::whereDay('updated_at', '=', 1)
    ->orWhereDay('updated_at', '=', 2); 

loadMissing()メソッドが追加されました

リレーションがloadingしてない時だけloadingしてくれます。


public function format(Book $book)
{
    // リレーション先のauthorのloading(loadingされてないときだけ)
    $book->loadMissing('author');

    return [
        'name' => $book->name,
        'author' => $book->author->name
    ];
}

Laravel5.7以降

ページネーションの中央のリンクに対するサイドの数を設定出来るようになりました。

デフォルトは3になります。

// [1][2][3]...[6][7][8]【10】[11][12][13]...[20][21][22]
User::paginate(10)

// [1][2][3]...[9]【10】[11]...[20][21][22]
User::paginate(10)->onEachSide(1); 

CollectionにwhenEmpty()whenNotEmpty()unlessEmpty()unlessNotEmpty()メソッドが追加されました

whenEmpty()の処理はコレクションが空の時にコールバックが呼ばれます。


$collection = new Collection;

$collection->whenEmpty(function ($collection) {
    return $collection->push('test');
});

$this->assertSame(['test'], $collection->toArray());

unlessEmpty()の処理はコレクションが空でない時にコールバックが呼ばれます。


$collection = new Collection;

$collection->unlessEmpty(function ($collection) {
    return $collection->push('abcd');
});

$this->assertSame([], $collection->toArray());

今年だけでも色々追加されてますね!
注意深く追っていかないと、気付かない機能もたくさんありそうです!!

#Eloquent+collectionで実現する機能
前提としてクエリで出来ることはクエリに任せる方が良いと思っているのですが、
データ量が少なくて再利用で済ませたい時やクエリ発行数を気にする時などは
collectionの機能でまかなう方が良い事も多々あると思います。

OrderBySortBysortByDesc

$flights = App\Flight::where('active', 1)
               ->orderBy('name', 'desc')
               ->get();

上でやってることは下でも
出来ます。

$flights = App\Flight::where('active', 1)
               ->get();
$sorted = $flights->sortByDesc('name');

単純に重複なしにするだけでいいなら全部取ってからuniqueでもいい

orderByとかDISTINCTを意識せずにやる

$comments = App\UserComment::get();
$commentCount = $comments->unique('user_id');

ある条件で1レコード目だけ抜きたい時

下手に条件付けてクエリに書かずに、データ取ってきてshiftとかするのもありかも

$users = App\User::where('active', 1)->get();
$shiftUser = $users->shift();

レコードを更新順に並べて取得して重複を無くす

取得したタイミングで一緒にuniqueまでする。

$comments = App\UserComment::orderBy('updated_at', 'desc')
                             ->get()
                             ->unique('user_id');

最後に

Laravelを使い始めた当初、collectionの機能の理解が乏しかったため、eloquentとcollectionを使ったベストプラクティスが出来てなかったと思います。

何でもクエリで取ってきて解決させれば良いという事はなくて、バランスよく各機能を使っていく判断が出来るよう情報のキャッチアップとtry&errorを続けていきたいと思います!

来年はLaravel JP Conferenceも初の開催がありますし、もっとLaravelが盛り上がっていければと思います!!

14
2
1

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
14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?