PHP
laravel
FunctionalProgramming

Laravel 5.4で追加された「Higher Order Messages」がすごい

Laravel 5.4 で追加された Higher Order Messages を使ってけっこう感動した。

https://laravel.com/docs/5.5/collections#higher-order-messages

Laravelのコレクションに対して、クロージャーを使わずに様々な処理を行えるもの。

具体例で説明したい。

前提

CompanyUser というモデルがあるとする。

  • Company hasMany Users
  • User belongsTo Company

という関係。

Company モデルには

  • 契約期限が切れているかを判定する getIsContractExpiredAttribute
  • 契約期限が切れている企業の各社員にメールする notifyContractExpiration

というメソッドが生えている、とする。で、

  • 契約期限が切れた Company をランダムに5件取得
  • その Company の社員に対して、契約期限切れのメールを送りたい

となったとする。

(色々おかしいと思いますが、コレクションの説明のため)

Before (~ 5.3)

Company::with('users')
    ->all()
    ->filter(function ($company) {
        return $company->isContractExpired;
    })
    ->take(5)
    ->pluck('users')->flatten()
    ->each(function ($user) {
        $user->notifyContractExpiration();
    });


After (5.4 ~)

Company::with('users')
    ->all()
    ->filter->isContractExpired
    ->take(5)
    ->flatMap->users
    ->each->notifyContractExpiration();

クロージャーが減ってめちゃくちゃ気持ち良い。

また、後者ではしれっと flatMap も使っている。これも便利。

ちょっと解説

上の例で Company::all()->map とすると、 Illuminate\Support\HigherOrderCollectionProxy というものが返ってきて、これが色々やってくれるっぽい。

この機能が使えるメソッドは以下の通り。

  • average
  • avg
  • contains
  • each
  • every
  • filter
  • first
  • flatMap
  • map
  • partition
  • reject
  • sortBy
  • sortByDesc
  • sum

上記の例で、例えば Company::all()->sum->isContractExpired とすると、契約期限が切れた企業の総数が返ってくる。

SQLみたいで楽しい。