Laravel Version: 5.5.40
PHP Version: 7.1.20
Queue driver: redis/horizon
I want to conditionally push listeners to queue but even when I add the queue method to my listener, I see the listener added to the queue (in horizon).
Here is my listener code:
<?php
namespace App\Listeners;
use App\Events\PostHasNewComment;
use App\Notifications\YouWereMentioned;
use Illuminate\Contracts\Queue\ShouldQueue;
class NotifyMentionedUsers implements ShouldQueue
{
public function __construct()
{
}
public function queue($queue, $job, $data)
{
$event = unserialize($data['data'])[0];
if (!$event->mentionedUsers) {
return false;
}
$queue->push($job, $data);
}
public function handle(PostHasNewComment $event)
{
if ($event->mentionedUsers) { // so this line can be removed if the queue method works!
$event->mentionedUsers
->filter(function ($user) use ($event) {
return $user->id !== (int)$event->comment->user_id;
})
->each(function ($user) use ($event) {
$user->notify(new YouWereMentioned($event->comment));
});
}
}
}
Add a shouldQueue method, it receives the $event as an argument and should return a boolean.
@themsaid Thanks! I removed the queue method and added shouldQueue and it works now. I can verify it using horizon. But is it possible to verify it in my test? My Event has multiple Listeners and I can only see the first one with the following test:
/** @test */
public function if_no_one_is_mentioned_then_the_notify_mentioned_users_should_not_be_queued()
{
Queue::fake();
$john = factory('App\User')->create(['username' => 'JohnDoe']);
$post = factory('App\Post')->create();
$response = $this->actingAs($john)->json('POST',
route('comments.store', [$post->id]), [
'body' => 'no one mentioned here'
]
);
Queue::assertPushed(CallQueuedListener::class, function ($job) {
// dd($job->class); this only has the first listener which is NotifyBlogOwner
return $job->class == NotifyMentionedUsers::class;
});
}
does Queue::assertPushed(CallQueuedListener::class, function ($job){}); iterates through the jobs? because the test passes but if I do the dd() I can only see the first listener.
If shouldQueue returned false the listener won't be queued at all, not sure if I understand your concern :)
@themsaid I mean how can I test it. Given I have a comment that has mentioned users I want to assert that the listener for notifyingMentiinedUsers gets added to the queue. And also the opposite to assert the listener not sent to queue if no one mentioned.
I have tested everything but just need to assert that the listener did not go to queue and the opposite when the listener does go to queue I want to assert that in my tests
https://laravel.com/docs/5.5/mocking#queue-fake might be what your looking for.
@rs-sliske @themsaid I did a Log and found that the Queue::assertPushed(CallQueuedListener::class, function ($job) {} does iterate through the jobs so I have to do that 2 times one to check if it has a job and the other time if it does not have the other one
Queue::assertPushed(CallQueuedListener::class, function ($job) {
return $job->class == ListenerThatShouldQueue::class;
});
Queue::assertNotPushed(CallQueuedListener::class, function ($job) {
return $job->class == ListenerThatShouldNotQueue::class;
});
Thanks @themsaid for the help :+1:
Most helpful comment
Add a
shouldQueuemethod, it receives the $event as an argument and should return a boolean.