Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publishing of Messenger events after Global State setup #519

Closed
benr77 opened this issue Nov 11, 2023 · 2 comments
Closed

Publishing of Messenger events after Global State setup #519

benr77 opened this issue Nov 11, 2023 · 2 comments

Comments

@benr77
Copy link

benr77 commented Nov 11, 2023

Hi Kevin. I've spent the last few days implementing Foundry on a big project, and really getting to grips with all it's wonderful features. I completely love it, so thank you for all your efforts with the package.

One thing I'm a bit stuck on is publishing my domain events that are created in my Global Story.

The application works as follows:

  1. Domain events are recorded when an entity is created or modified.
  2. These events are then persisted in the same transaction as the entity.
  3. There is a listener in kernel.terminate which publishes the events to the message bus.
  4. In some cases, an event handler then creates a secondary entity, and persists it.

When Global Story is executed and the main entities are persisted, the events are also recorded and persisted.

However, this means when my test subsequently executes, because the events have not yet been published, these secondary entities have not yet been created .

If I then create the secondary entity manually inside the test using a Foundry Factory, it works. However, when the event is finally published (e.g. during a secondary browse request) it complains that an entity with the given ID already exists.

My current solution is messy and makes the test slower - I add an extra request to the test before visiting the route under test:

$this->browser()
    ->visitRoute('homepage') // To trigger domain event publishing
    ->visitRoute('route_under_test')
;

Can you suggest an appropriate method to handle this situation? I think maybe some method of rebooting the kernel after Global Story but before any tests are executed might be the way to go, but this might well confuse Foundry itself. Or would it maybe be better to have a second Global Story service that actively publishes the events without waiting for kernel.terminate?

A lot of my entities are created based on domain events from another entity, so having all this work seamlessly like it does in the production code would be much more elegant.

Thanks!

@nikophil
Copy link
Member

nikophil commented Nov 11, 2023

Hi,

I think you can use an invokable service as a global state for this, it would be the last global state used, and will trigger those events:

    zenstruck_foundry:
        global_state:
            - App\Tests\YourGlobalStory
            - App\Tests\MaybeAnotherGlobalStory
            - ...
            
            # you can add here a service name (which must be invokable)
            # and it should do the same stuff than your listener for `kernel.terminate` does
            - some.invokable.global.state

@benr77
Copy link
Author

benr77 commented Nov 12, 2023

Yes, this is the solution I have gone for and it's now working well. Much more elegant!

I have created an invokable service, and then refer to it in the global_state configuration as the last entry.

final readonly class DomainEventFixturePublisher
{
    public function __construct(
        private DomainEventPublisher $publisher
    ) {
    }

    public function __invoke(): void
    {
        echo "Publishing domain events... ";

        $this->publisher->publish();

        echo "done\n";
    }
}

@benr77 benr77 closed this as completed Nov 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants