Skip to content

Commit

Permalink
Merge pull request #365 from spatie/add-weight-to-handlers
Browse files Browse the repository at this point in the history
Support weight property to event handlers
  • Loading branch information
freekmurze authored Sep 12, 2022
2 parents 60e232f + 1397dc8 commit 8bab406
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,25 @@ You can set the name of the queue connection in the `queue` key of the `event-so

In a local environment, where events have a very low chance of getting fired concurrently, it's probably ok to just use the `sync` driver.

## Tweaking projector order

You can add a weight property to a projector to tweak the order projectors are run in. Projectors with a lower weight run first. When no explicit weight is provided, the weight is considered `0`.

```php
namespace App\Projectors;

use Spatie\EventSourcing\EventHandlers\Projectors\Projector;

class MyProjector extends Projector
{
public int $weight = 5;

//
}
```

Note that providing a weight on a queued projector won't guarentee execution order.

## Want to know more?

We discuss projections and complex patterns such as CQRS in depth in our [Event Sourcing in Laravel](https://event-sourcing-laravel.com/) course. In practice, you want to check out these chapters:
Expand Down
15 changes: 15 additions & 0 deletions docs/using-reactors/creating-and-configuring-reactors.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,21 @@ class SendMoneyAddedMail
}
```

## Tweaking reactor order

You can add a weight property to a reactor to tweak the order reactors are run in. Reactors with a lower weight run first. When no explicit weight is provided, the weight is considered `0`.

```php
namespace App\Reactors;

class MyReactor
{
public int $weight = 5;
}
```

Note that providing a weight on a queued reactor won't guarentee execution order.

## Want to know more?

Reactors and process managers (which are built on top of the core reactor principle) are thoroughly discussed in [Event Sourcing in Laravel](https://event-sourcing-laravel.com/). More specifically, you want to read these chapters:
Expand Down
20 changes: 14 additions & 6 deletions src/EventHandlers/EventHandlerCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,23 @@ public function remove(array $eventHandlerClassNames): void

public function syncEventHandlers(): self
{
return $this ->reject(
fn (EventHandler $eventHandler) => $eventHandler instanceof ShouldQueue
);
return $this
->reject(
fn (EventHandler $eventHandler) => $eventHandler instanceof ShouldQueue
)
->sortBy(
fn (EventHandler $eventHandler) => $eventHandler->weight ?? 0
);
}

public function asyncEventHandlers(): self
{
return $this->filter(
fn (EventHandler $eventHandler) => $eventHandler instanceof ShouldQueue
);
return $this
->filter(
fn (EventHandler $eventHandler) => $eventHandler instanceof ShouldQueue
)
->sortBy(
fn (EventHandler $eventHandler) => $eventHandler->weight ?? 0
);
}
}
12 changes: 3 additions & 9 deletions tests/EventSerializers/EventSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,9 @@ public function it_serializes_an_event_to_json()

$array = json_decode($json, true);

$this->assertEquals([
'account' => [
'class' => get_class($account),
'id' => 1,
'relations' => [],
'connection' => $this->dbDriver(),
],
'amount' => 1234,
], $array);
$this->assertEquals(get_class($account), $array['account']['class'] ?? null);
$this->assertEquals(1, $array['account']['id'] ?? null);
$this->assertEquals(1234, $array['amount'] ?? null);
}

/** @test */
Expand Down
25 changes: 25 additions & 0 deletions tests/ProjectionistTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@
use Spatie\EventSourcing\Tests\TestClasses\Projectors\FakeMoneyAddedCountProjector;
use Spatie\EventSourcing\Tests\TestClasses\Projectors\MoneyAddedCountProjector;
use Spatie\EventSourcing\Tests\TestClasses\Projectors\ProjectorThatThrowsAnException;
use Spatie\EventSourcing\Tests\TestClasses\Projectors\ProjectorWithHighWeight;
use Spatie\EventSourcing\Tests\TestClasses\Projectors\ProjectorWithLowWeight;
use Spatie\EventSourcing\Tests\TestClasses\Projectors\ProjectorWithNegativeWeight;
use Spatie\EventSourcing\Tests\TestClasses\Projectors\ProjectorWithoutWeight;
use Spatie\EventSourcing\Tests\TestClasses\Projectors\QueuedProjector;
use Spatie\EventSourcing\Tests\TestClasses\ProjectorWithWeightTestHelper;
use Spatie\EventSourcing\Tests\TestClasses\Reactors\BrokeReactor;

class ProjectionistTest extends TestCase
Expand Down Expand Up @@ -76,6 +81,26 @@ public function it_will_call_the_method_on_the_projector_when_the_projector_thro
$this->assertEquals(1, ProjectorThatThrowsAnException::$exceptionsHandled);
}

/** @test */
public function it_will_call_projectors_ordered_by_weight()
{
app()->singleton(ProjectorWithWeightTestHelper::class);

Projectionist::addProjector(ProjectorWithHighWeight::class);
Projectionist::addProjector(ProjectorWithoutWeight::class);
Projectionist::addProjector(ProjectorWithNegativeWeight::class);
Projectionist::addProjector(ProjectorWithLowWeight::class);

event(new MoneyAddedEvent($this->account, 1000));

$this->assertSame([
ProjectorWithNegativeWeight::class,
ProjectorWithoutWeight::class,
ProjectorWithLowWeight::class,
ProjectorWithHighWeight::class,
], app(ProjectorWithWeightTestHelper::class)->calledBy);
}

/** @test */
public function it_can_catch_exceptions_and_still_continue_calling_other_projectors()
{
Expand Down
13 changes: 13 additions & 0 deletions tests/TestClasses/ProjectorWithWeightTestHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Spatie\EventSourcing\Tests\TestClasses;

class ProjectorWithWeightTestHelper
{
public array $calledBy = [];

public function calledBy(string $className): void
{
$this->calledBy[] = $className;
}
}
22 changes: 22 additions & 0 deletions tests/TestClasses/Projectors/ProjectorWithHighWeight.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Spatie\EventSourcing\Tests\TestClasses\Projectors;

use Spatie\EventSourcing\EventHandlers\Projectors\Projector;
use Spatie\EventSourcing\Tests\TestClasses\Events\MoneyAddedEvent;
use Spatie\EventSourcing\Tests\TestClasses\ProjectorWithWeightTestHelper;

class ProjectorWithHighWeight extends Projector
{
public int $weight = 5;

public function __construct(
private ProjectorWithWeightTestHelper $projectorWithWeightTestHelper,
) {
}

public function onMoneyAdded(MoneyAddedEvent $event): void
{
$this->projectorWithWeightTestHelper->calledBy(static::class);
}
}
22 changes: 22 additions & 0 deletions tests/TestClasses/Projectors/ProjectorWithLowWeight.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Spatie\EventSourcing\Tests\TestClasses\Projectors;

use Spatie\EventSourcing\EventHandlers\Projectors\Projector;
use Spatie\EventSourcing\Tests\TestClasses\Events\MoneyAddedEvent;
use Spatie\EventSourcing\Tests\TestClasses\ProjectorWithWeightTestHelper;

class ProjectorWithLowWeight extends Projector
{
public int $weight = 1;

public function __construct(
private ProjectorWithWeightTestHelper $projectorWithWeightTestHelper,
) {
}

public function onMoneyAdded(MoneyAddedEvent $event): void
{
$this->projectorWithWeightTestHelper->calledBy(static::class);
}
}
22 changes: 22 additions & 0 deletions tests/TestClasses/Projectors/ProjectorWithNegativeWeight.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Spatie\EventSourcing\Tests\TestClasses\Projectors;

use Spatie\EventSourcing\EventHandlers\Projectors\Projector;
use Spatie\EventSourcing\Tests\TestClasses\Events\MoneyAddedEvent;
use Spatie\EventSourcing\Tests\TestClasses\ProjectorWithWeightTestHelper;

class ProjectorWithNegativeWeight extends Projector
{
public int $weight = -5;

public function __construct(
private ProjectorWithWeightTestHelper $projectorWithWeightTestHelper,
) {
}

public function onMoneyAdded(MoneyAddedEvent $event): void
{
$this->projectorWithWeightTestHelper->calledBy(static::class);
}
}
20 changes: 20 additions & 0 deletions tests/TestClasses/Projectors/ProjectorWithoutWeight.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Spatie\EventSourcing\Tests\TestClasses\Projectors;

use Spatie\EventSourcing\EventHandlers\Projectors\Projector;
use Spatie\EventSourcing\Tests\TestClasses\Events\MoneyAddedEvent;
use Spatie\EventSourcing\Tests\TestClasses\ProjectorWithWeightTestHelper;

class ProjectorWithoutWeight extends Projector
{
public function __construct(
private ProjectorWithWeightTestHelper $projectorWithWeightTestHelper,
) {
}

public function onMoneyAdded(MoneyAddedEvent $event): void
{
$this->projectorWithWeightTestHelper->calledBy(static::class);
}
}

0 comments on commit 8bab406

Please sign in to comment.