I’m building an API with Laravel and want to send push notification using the Laravel Notifications system. I’ve a model for matches (which is basically a post), another user can like this match. When the match is liked, the creator of the post will get a push notification. It’s just like Instagram, Facebook, etc.
Often the push notification wasn’t send to the user. I installed Laravel Horizon to see if there where errors. Sometimes the notification was send and sometimes it wasn’t. With the exact same data:
The notification fails sometimes with the exact same data (same user, same match).
The error is as followed:
IlluminateDatabaseEloquentModelNotFoundException: No query results
for model [AppModelsMatch] 118 in
/home/forge/owowgolf.com/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:312
I’m sure the match and the user exists in the database, I’ve verified that before sending the notification. Does anybody know what’s going wrong? Everything I could find online is that people didn’t save their model before sending the notification into the queue. But the line where the code send’s the notification into the queue wouldn’t even be reached if the model didn’t exists. Because of Implicit Binding in the route/controller.
Controller method:
/**
* Like a match.
*
* @param AppModelsMatch $match
* @return IlluminateHttpJsonResponse
*/
public function show(Match $match)
{
$match->like();
$players = $match->players()->where('user_id', '!=', currentUser()->id)->get();
foreach ($players as $user) {
$user->notify(new NewLikeOnPost($match, currentUser()));
}
return ok();
}
Notification:
<?php
namespace AppNotifications;
use AppModelsMatch;
use AppModelsUser;
use IlluminateBusQueueable;
use NotificationChannelsApnApnChannel;
use NotificationChannelsApnApnMessage;
use IlluminateNotificationsNotification;
use IlluminateContractsQueueShouldQueue;
class NewLikeOnPost extends Notification implements ShouldQueue
{
use Queueable;
/**
* The match instance.
*
* @var AppModelsMatch
*/
private $match;
/**
* The user instance.
*
* @var AppModelsUser
*/
private $user;
/**
* Create a new notification instance.
*
* @param AppModelsMatch $match
* @param AppModelsUser $user
*/
public function __construct(Match $match, User $user)
{
$this->user = $user;
$this->match = $match;
$this->onQueue('high');
}
/**
* Get the notification's delivery channels.
*
* @param AppModelsUser $notifiable
* @return array
*/
public function via($notifiable)
{
if ($notifiable->wantsPushNotification($this)) {
return ['database', ApnChannel::class];
}
return ['database'];
}
/**
* Get the mail representation of the notification.
*
* @param AppModelsUser $notifiable
* @return NotificationChannelsApnApnMessage
*/
public function toApn($notifiable)
{
return ApnMessage::create()
->badge($notifiable->unreadNotifications()->count())
->sound('success')
->body($this->user->username . ' flagged your match.');
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
'user_id' => $this->user->id,
'body' => "<flag>Flagged</flag> your match.",
'link' => route('matches.show', $this->match),
'match_id' => $this->match->id,
];
}
/**
* Get the match attribute.
*
* @return AppModelsMatch
*/
public function getMatch()
{
return $this->match;
}
}
3
Answers
Check your .env to be sure that u really use REDIS
then clear cache (
php artisan cache:clear , php artisan view:clear
), that should clear the issueEDIT
I had similar problems but now I use Docker only and before I had to check for cached configfiles, wrong file/folderpermissions and so on (REDIS for broadcast only, others were standard). I started using redis only – that`s a lot easier, faster and more debugfriendly for me ! And together with Docker really helpful to not use messed up nginx/apache/php/redis/ …
Its probably because $user is not an object of User model, its an object of Match model. You need to do a User::findorfail or User::firstOrFail then notify the user.
}
Unless the notify trait is used in Match model. Or you could use eager loading which will cost way less queries!
This is not a complete solution, but it will lower your chances of running into this error in the future.
Instead of passing in the whole
Match
model into the job, only pass theid
of the model. You can then fetch that model in the constructor.Notification:
You can use the
SerializesModels
trait, but it doesn’t work well when you add a delay to a queued job. This is because it will try to reload the model on__wakeup()
and sometimes it cannot find the class.Hopefully this helps 🙂