Laravel使用@can指令时触发Query\Builder::isLeader未定义错误
让我们先梳理下你遇到的场景:
你之前在Blade模板里用这段代码是正常运行的:
@if(Auth::user()->isLeader()) <input type='hidden' name='leader' value='{{ Auth::id() }}'> @endif
为了简化代码,你参照Laravel文档改用@can指令,先在AuthServiceProvider里定义了名为isLeader的Gate:
public function boot() { $this->registerPolicies(); Gate::define('isLeader', function ($user) { return $user->isLeader(); }); }
然后把Blade代码改成了:
@can('isLeader') <input type='hidden' name='leader' value='{{ Auth::id() }}'> @cannot
结果打开模板页面直接触发错误:
"Call to undefined method Illuminate\Database\Query\Builder::isLeader()"
你的User模型里isLeader方法是这么实现的:
public function isLeader() { $leader = static::where('id','=',$this->id)->leader(); if($leader->count() == 0){ return false; } return true; }
错误原因解析
这个错误的核心不是@can指令或者Gate的定义问题——本质上,Gate只是帮你调用了$user->isLeader(),和你之前@if里的调用逻辑完全一致。真正的问题出在你的isLeader方法内部:
你在方法里写了static::where('id','=',$this->id)->leader(),这里的static::where(...)返回的是一个Illuminate\Database\Query\Builder实例,而你紧接着调用的leader()方法,既不是Query Builder内置的方法,也不是你给Query Builder扩展的方法,所以PHP会抛出"方法未定义"的错误。
另外,从逻辑上看这段代码也有冗余:static::where('id','=',$this->id)其实就是在查询当前用户自己(因为$this->id就是当前模型实例的ID),完全没必要用查询构造器,直接用$this即可。如果你的leader()是一个模型关联方法(比如你定义了一个leader关联),那应该写成$this->leader()而不是通过查询构造器去调用。
顺带提一句:你Blade里的结尾标签写错了,@cannot应该改成@endcan,不过这个语法错误不会导致当前的方法未定义错误,只是会引发Blade解析错误。
内容的提问来源于stack exchange,提问作者Adam

