Skip to content

Commit

Permalink
Add Mount Hook and allow classnames in registration
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielCoulbourne committed Nov 7, 2024
1 parent 7ec1450 commit dc6b725
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 7 deletions.
17 changes: 13 additions & 4 deletions examples/Bank/src/Events/AccountOpened.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

namespace Thunk\Verbs\Examples\Bank\Events;

use Illuminate\Support\Facades\Mail;
use Thunk\Verbs\Attributes\Autodiscovery\StateId;
use Thunk\Verbs\Event;
use Thunk\Verbs\Examples\Bank\Mail\WelcomeEmail;
use Thunk\Verbs\Facades\Verbs;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Mail;
use Thunk\Verbs\Examples\Bank\Models\Account;
use Thunk\Verbs\Examples\Bank\Mail\WelcomeEmail;
use Thunk\Verbs\Attributes\Autodiscovery\StateId;
use Thunk\Verbs\Examples\Bank\States\AccountState;
use Thunk\Verbs\Facades\Verbs;

class AccountOpened extends Event
{
Expand Down Expand Up @@ -39,4 +40,12 @@ public function handle()

Verbs::unlessReplaying(fn () => Mail::send(new WelcomeEmail($this->user_id)));
}

public static function migrate()
{
return [
1 => fn(Collection $v0) => $v0->except('user_id'),
2 => fn(Collection $v1) => $v1->merge(['email' => '[email protected]']),
];
}
}
2 changes: 2 additions & 0 deletions src/Contracts/BrokersEvents.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ public function isAuthorized(Event $event): bool;
public function isValid(Event $event): bool;

public function replay(?callable $beforeEach = null, ?callable $afterEach = null);

public function registerListener(string|object $target);
}
1 change: 1 addition & 0 deletions src/Facades/Verbs.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* @method static EventStoreFake assertNothingCommitted()
* @method static CarbonInterface realNow()
* @method static void skipPhases(Phase ...$phases)
* @method static void registerListener(string|object $target)
*/
class Verbs extends Facade
{
Expand Down
7 changes: 7 additions & 0 deletions src/Lifecycle/Broker.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public function fire(Event $event): ?Event
return null;
}

$this->dispatcher->mount($event);

// NOTE: Any changes to how the dispatcher is called here
// should also be applied to the `replay` method

Expand Down Expand Up @@ -121,4 +123,9 @@ public function skipPhases(Phase ...$phases): void
{
$this->dispatcher->skipPhases(...$phases);
}

public function registerListener(string|object $target): void
{
$this->dispatcher->register($target);
}
}
26 changes: 25 additions & 1 deletion src/Lifecycle/Dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function __construct(
protected Container $container
) {}

public function register(object $target): void
public function register(string|object $target): void
{
foreach (Reflector::getHooks($target) as $hook) {
foreach ($hook->events as $event_type) {
Expand All @@ -38,6 +38,17 @@ public function skipPhases(Phase ...$phases): void
$this->skipped_phases = $phases;
}

public function mount(Event $event): bool
{
if (! $this->shouldDispatchPhase(Phase::Mount)) {
return true;
}

$this->getMountHooks($event)->each(fn (Hook $hook) => $hook->mount($this->container, $event));

return true;
}

public function validate(Event $event): bool
{
if (! $this->shouldDispatchPhase(Phase::Validate)) {
Expand Down Expand Up @@ -85,6 +96,19 @@ public function replay(Event $event): void
}
}

/** @return Collection<int, Hook> */
protected function getMountHooks(Event $event): Collection
{
$hooks = $this->hooksFor($event, Phase::Mount);

if (method_exists($event, 'mount')) {
dump($event);
$hooks->prepend(Hook::fromClassMethod($event, 'mount')->forcePhases(Phase::Mount));
}

return $hooks;
}

/** @return Collection<int, Hook> */
protected function getFiredHooks(Event $event): Collection
{
Expand Down
11 changes: 10 additions & 1 deletion src/Lifecycle/Hook.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class Hook
{
public static function fromClassMethod(object $target, ReflectionMethod|string $method): static
public static function fromClassMethod(string|object $target, ReflectionMethod|string $method): static
{
if (is_string($method)) {
$method = new ReflectionMethod($target, $method);
Expand Down Expand Up @@ -72,6 +72,15 @@ public function runsInPhase(Phase $phase): bool
return isset($this->phases[$phase]) && $this->phases[$phase] === true;
}

public function mount(Container $container, Event $event): bool
{
if ($this->runsInPhase(Phase::Mount)) {
return $this->execute($container, $event) ?? true;
}

throw new RuntimeException('Hook::mount called on a non-mount hook.');
}

public function validate(Container $container, Event $event): bool
{
if ($this->runsInPhase(Phase::Validate)) {
Expand Down
1 change: 1 addition & 0 deletions src/Lifecycle/Phase.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

enum Phase: string
{
case Mount = 'mount';
case Authorize = 'authorize';
case Validate = 'validate';
case Apply = 'apply';
Expand Down
2 changes: 1 addition & 1 deletion src/Support/Reflector.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
class Reflector extends BaseReflector
{
/** @return Collection<int, Hook> */
public static function getHooks(object $target): Collection
public static function getHooks(string|object $target): Collection
{
if ($target instanceof Closure) {
return collect([Hook::fromClosure($target)]);
Expand Down
5 changes: 5 additions & 0 deletions src/Testing/BrokerFake.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,9 @@ public function commitImmediately(bool $commit_immediately = true): void
{
$this->broker->commitImmediately($commit_immediately);
}

public function registerListener(string|object $target): void
{
$this->broker->registerListener($target);
}
}
34 changes: 34 additions & 0 deletions tests/Feature/MountHookTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

use Thunk\Verbs\Attributes\Hooks\On;
use Thunk\Verbs\Event;
use Thunk\Verbs\Facades\Verbs;
use Thunk\Verbs\Lifecycle\Phase;


it('can modify props on events in the mount phase', function () {
Verbs::registerListener(Listener::class);

$e = EventWithNullProp::fire(
album: 'Tha Carter 2'
);

expect($e)
->name
->toBe('Lil Wayne');
});

class EventWithNullProp extends Event
{
public ?string $name = null;
public string $album;
}

class Listener
{
#[On(Phase::Mount)]
public static function setNameToLilWayne(EventWithNullProp $event)
{
$event->name = 'Lil Wayne';
}
}

0 comments on commit dc6b725

Please sign in to comment.