Laravel 今までのローカルスコープの書き方と今後のモダンな書き方
前書き
Laravel のローカルスコープの書き方について、今後はこんな風になるのではないか、と勝手に予想する小ネタ的な記事です😅 今までの書き方が無効になるとかいう訳では無く、スタイル的な話です。また、記事後半では、少し話が Larastan に逸れていきます。
本題
Laravel のローカルスコープと言えば、現在、一番よく見る書き方と言えば、こんな感じかと思います。
class User extends Model
{
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
}
特に問題無いですね。ですがここ最近、海外のサイトなどを見ていると、こんな会話も見られるようになりました。
A 「ここの return 文って、return する必要無くない?」
B 「んだな~(そうだね)」
ということで、return は、カットしてしまいましょう。
進化形1、return はカット
class User extends Model
{
public function scopePopular($query)
{
$query->where('votes', '>', 100);
}
}
Laravel 7 のドキュメントでは、return 付きでしたが、現在の Laravel 8&9では、return ありと無しの両方が併記されています。ですが、Laravel 10 のドキュメントでは、return 無しに統一される予定です。
まぁ、return があると何か精神的に落ち着く所はあるかも知れませんが、内部的には、$query を return してもしなくてもどっちでも良いようにできています。(オブジェクトは参照渡しだし)
進化形2、型を書く
Laravel 10 から、かなり型を意識させる感じになっています。ということで、今後は下記の書き方が流行って行くと思われます。実際、下記が Laravel 10 のドキュメントに記載される予定です。
use Illuminate\Database\Eloquent\Builder;
class User extends Model
{
public function scopePopular(Builder $query): void
{
$query->where('votes', '>', 100);
}
}
Eloquent\Builder って、何?となりそうですね。簡単な説明としては、Laravel には、Collection とそれを拡張した Eloquent 用の Eloquent Collection があるように、クエリ文を構築してくれる Query\Builder を元にした Eloquent 用の Eloquent\Builder がある、って感じですね。
進化形3、Larastan も考慮
昨今流行りつつある静的解析の Larastan(PHPStan)のレベル 6~9(執筆現在)を満たそうとすると更に記述が必要になり、下記のようになります。
use Illuminate\Database\Eloquent\Builder;
class User extends Model
{
+ /**
+ * @param Builder<User> $query
+ */
public function scopePopular(Builder $query): void
{
$query->where('votes', '>', 100);
}
}
ふ~ん、って感じになってきましたが、上記で EloquentBuilder と User モデルが紐付く事を教えてやると、Larastan がエラーを出さなくなります。
そうでないと、下記のようなエラーが出ます。
Method App\Models\User::scopePopular() has parameter $query with generic class Illuminate\Database\Eloquent\Builder but does not specify
its types: TModelClass
💡 You can turn this off by setting checkGenericClassInNonGenericObjectType: false in your phpstan.neon.
このエラーが出ないように設定する事も可能な一方、敢えて上記のように書くと何か良くなる事があるのでしょうか? (・_・")?
良くなる事
ありました。Larastan のまだベータとされる checkModelProperties という機能をオンにしてみます。
parameters:
checkModelProperties: true
そして、例えば手が滑って votes
と書く所を votes999
と書いてしまったとします。
/**
* @param Builder<User> $query
*/
public function scopePopular(Builder $query): void
{
$query->where('votes999', '>', 100);
}
そうすると、Larastan 先生が、
Property 'votes999' does not exist in App\Models\User model.
とエラーを表示してくれるようになります。
Larastan は、User モデルと紐付くと分かった為、User 用のマイグレーションを調べ、「そんなフィールド無いよ!」と教えてくれている訳です。これはちょっと嬉しいですね。
ちなみに、マイグレーションファイルのみ更新しても、キャッシュを見てしまう場合は、--debug オプションを付けて1度実行するといいです。
後書き
流石に進化形3になると「ちょっと小面倒だな…。もう AI がやってくれよ! ヽ(´・д・`)ノ」と思う所もあります😅
間違い等ありましたらコメント下さい🙇♂️
Discussion