Laravel 5.8+Backpack 3.5中auth()获取未读通知为空问题求助
这个问题的核心原因大概率是认证守卫返回的用户实例的模型形态类(morph class)和数据库中通知记录的notifiable_type不匹配,导致查询不到数据。
具体原因拆解
你用\App\User::find(auth()->user()->id)能拿到正确的通知,是因为这个方式直接从App\User模型发起查询,生成的SQL会用App\User作为notifiable_type的查询条件,和你数据库里已有的通知记录完全匹配。
但用auth()->user()->unreadNotifications()时,由于你通过中间件把默认认证守卫替换成了Backpack的守卫,auth()->user()返回的用户实例可能不是App\User类,而是Backpack自带的Backpack\Base\app\Models\BackpackUser类(或者你自定义的其他Backpack用户模型)。此时Laravel的通知关联会用这个实例的getMorphClass()返回值作为notifiable_type的查询条件,和数据库里存的App\User不匹配,自然查不到数据。
快速验证方法
你可以在控制器里临时加一行代码,输出当前auth()->user()的类名,确认问题:
dd(get_class(auth()->user()));
如果输出的不是App\User,那就是这个问题无疑了。
两种解决方案
根据你的实际需求,可选以下两种处理方式:
方案1:让Backpack使用你的App\User作为用户模型
修改config/backpack/base.php配置文件中的user_model_fqn项,指定为你的用户模型:
'user_model_fqn' => App\User::class,
这样auth()->user()就会返回App\User实例,和数据库里的通知记录的notifiable_type完全匹配,查询就能正常工作了。
方案2:修改Backpack用户模型的形态类(如果必须用Backpack自带模型)
如果你需要继续使用Backpack的BackpackUser模型,可以在该模型中重写getMorphClass()方法,让它返回App\User,这样关联查询时就会用正确的notifiable_type:
use Backpack\Base\app\Models\BackpackUser as BaseUser; class BackpackUser extends BaseUser { public function getMorphClass() { return \App\User::class; } }
或者,如果你已经有大量历史通知记录,也可以直接修改数据库中notifications表的notifiable_type字段,把所有App\User替换为Backpack用户模型的类名(比如Backpack\Base\app\Models\BackpackUser)。
额外补充
你提到控制器其他部分auth()和backpack_auth()都正常工作,这是因为这两个守卫返回的用户实例的id是一致的,但模型类不同,才导致了通知关联查询的差异。
内容的提问来源于stack exchange,提问作者Librasulus

