Skip to content

Commit

Permalink
Add support for queued listeners
Browse files Browse the repository at this point in the history
See #87
  • Loading branch information
lorisleiva committed Mar 30, 2021
1 parent bd3ded4 commit 6e3c645
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/DesignPatterns/ListenerDesignPattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Lorisleiva\Actions\DesignPatterns;

use Illuminate\Events\CallQueuedListener;
use Illuminate\Events\Dispatcher;
use Lorisleiva\Actions\BacktraceFrame;
use Lorisleiva\Actions\Concerns\AsListener;
Expand All @@ -16,7 +17,10 @@ public function getTrait(): string

public function recognizeFrame(BacktraceFrame $frame): bool
{
return $frame->matches(Dispatcher::class, 'dispatch');
return $frame->matches(Dispatcher::class, 'dispatch')
|| $frame->matches(Dispatcher::class, 'handlerWantsToBeQueued')
|| $frame->matches(CallQueuedListener::class, 'handle')
|| $frame->matches(CallQueuedListener::class, 'failed');
}

public function decorate($instance, BacktraceFrame $frame)
Expand Down
75 changes: 75 additions & 0 deletions tests/AsListenerWithShouldQueueTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

namespace Lorisleiva\Actions\Tests;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Events\CallQueuedListener;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Queue;
use Lorisleiva\Actions\Concerns\AsListener;
use Lorisleiva\Actions\Tests\Stubs\OperationRequestedEvent;

class AsListenerWithShouldQueueTest implements ShouldQueue
{
use AsListener;

public static int $constructed = 0;
public static int $handled = 0;
public static ?int $latestResult;

public function __construct()
{
static::$constructed++;
}

public function handle(string $operation, int $left, int $right): int
{
static::$handled++;

return static::$latestResult = $operation === 'addition'
? $left + $right
: $left - $right;
}

public function asListener(OperationRequestedEvent $event): void
{
$this->handle($event->operation, $event->left, $event->right);
}
}

beforeEach(function () {
// Given we are listening for the OperationRequestedEvent.
Event::listen(OperationRequestedEvent::class, AsListenerWithShouldQueueTest::class);

// And reset the static properties between each test.
AsListenerWithShouldQueueTest::$constructed = 0;
AsListenerWithShouldQueueTest::$handled = 0;
AsListenerWithShouldQueueTest::$latestResult = null;
});

it('wraps the action in a CallQueuedListener', function () {
// Given we mock the queue.
Queue::fake();

// When we dispatch an OperationRequestedEvent.
Event::dispatch(new OperationRequestedEvent('addition', 1, 2));

// Then the action was pushed in the queue via a CallQueuedListener job.
Queue::assertPushed(CallQueuedListener::class, function (CallQueuedListener $job) {
return $job->class === AsListenerWithShouldQueueTest::class
&& $job->method === 'handle' // No worries here, it'll be wrapped in a ListenerDecorator.
&& $job->data[0] instanceof OperationRequestedEvent;
});
});

it('can run as a queued listener', function () {
// When we dispatch an OperationRequestedEvent.
Event::dispatch(new OperationRequestedEvent('addition', 1, 2));

// Then the action was triggered as a queued listener.
expect(AsListenerWithShouldQueueTest::$latestResult)->toBe(3);
expect(AsListenerWithShouldQueueTest::$handled)->toBe(1);

// And was constructed twice. Once before and once during the queued job.
expect(AsListenerWithShouldQueueTest::$constructed)->toBe(2);
});

0 comments on commit 6e3c645

Please sign in to comment.