Infrastructure and testing helpers for creating CQRS and event sourced applications.

Related tags

Event broadway
Overview

Broadway

Broadway is a project providing infrastructure and testing helpers for creating CQRS and event sourced applications. Broadway tries hard to not get in your way. The project contains several loosely coupled components that can be used together to provide a full CQRS\ES experience.

Build Status

About

Read the blog post about this repository at:

Installation

$ composer require broadway/broadway

Documentation

You can find detailed documentation of the Broadway bundle on broadway.github.io/broadway.

Feel free to join #qandidate on freenode with questions and remarks!

Acknowledgements

The broadway project is heavily inspired by other open source project such as AggregateSource, Axon Framework and Ncqrs.

We also like to thank Benjamin, Marijn and Mathias for the conversations we had along the way that helped us shape the broadway project. In particular Marijn for giving us access to his in-house developed CQRS framework.

License

MIT, see LICENSE.

Comments
  • [Suggestion] Remove the Interface suffix in interface names

    [Suggestion] Remove the Interface suffix in interface names

    See http://verraes.net/2013/09/sensible-interfaces/ for the argumentation. Note that most components are already using a descriptive name for the provided implementation rather than making it the priviledged one (for instance class SimpleEventBus implements EventBusInterface)

    Doing such should be done quickly, to avoid fighting with BC concerns with the current interface names.

    enhancement 
    opened by stof 36
  • Loading by id of a different aggregate

    Loading by id of a different aggregate

    Sorry if this is a silly question and I am missing something.

    Since the same table is used for all events in the event store: if I have two aggregates classes and I call EventSourcingRepository::load() on a repository for one aggregate class with an id belonging to an instance of the other aggregate class then there is no exception. Instead the events are played back against the wring type of entity and silently do nothing as there are no methods to handle them.

    Am I (a) doing something wrong to make this possible at all (b) missing something that should make this throw an exception (c) just needing to implement something that stops this within my aggregates?

    stale 
    opened by richardmiller-zz 27
  • MongoDB as EventStore

    MongoDB as EventStore

    Introducing support of MongoDB as EventStore.

    Features included in this PR:

    • read queries against primary nodes for strong data consistency
    • read committed isolation level to avoid reading partial event commits
    • test cases adopted for MongoDB
    opened by jaymecd 26
  • Projecting (using ES) fails if a ReadModel is renamed or moved to another namespace

    Projecting (using ES) fails if a ReadModel is renamed or moved to another namespace

    I have created several projections/read models and stored those in ElasticSearch using the ElasticSearch repository. Afterwards I decided to move the read models into another namespace and now the serializer fails because the class does not exist.

    I have traced the issue to this location: https://github.com/qandidate-labs/broadway/blob/master/src/Broadway/Serializer/SimpleInterfaceSerializer.php#L47

    Because this is a dev environment I have emptied my ElasticSearch instance and it works again so I am afraid I can no longer capture additional information but I hope this report helps to resolve this issue. I can imagine that during a refactoring this can also happen in a production environment.

    opened by mvriel 22
  • Component to replay event streams to event bus

    Component to replay event streams to event bus

    It would be nice to have a component that can replay all events from an event store (in historical order) to an event bus. This would facilitate a few use cases, like:

    • correcting faulty read models
    • initialize new read models

    We've already coded a callable class EventStream specific for DBAL (https://github.com/cultuurnet/udb3-php/commit/9af9770ca1bfa3976f977f802cb85a0f05d0132f) which returns a PHP Generator for iterating over all stored events in the right historical order, and it's used in a CLI command in our SIlex application (https://github.com/cultuurnet/udb3-silex/blob/feature/event-stream-replay/src/Console/ReplayCommand.php#L47). Unfortunately we had to copy quite some code from the DBAL EventStore to our class. Splitting up some methods like deserializeEvent() from the DBALEventStore to a separate class might be a good idea, or the EventStore interface itself could be extended to allow to retrieve all events. There are several possibilities. I'd be happy to discuss this a bit more with you.

    opened by cyberwolf 22
  • [Suggestion] Add Laravel integration

    [Suggestion] Add Laravel integration

    I will start working on a broadway integration for Laravel this week / month. Should I create a separate repository or, make a pull request once it's finished?

    opened by MarkRedeman 19
  • Solve issues with saga implementation

    Solve issues with saga implementation

    In this PR I have so far fixed the following problems:

    • Previously there was no way to register saga's automatically. I've added the RegisterSagaCompilerPass for this and you can use the broadway.saga service tag now.
    • Saga instances should be provided as the second argument of the MultipleSagaManager, for which there was no service definition yet. I've added it.
    • The SagaScenarioTestCase didn't conform to the other *TestCase classes in this library in that you had to create your own scenario. I changed this: it's now created for you. Since a saga is likely to use generated UUIDs, a sequence generator for them has been provided, so this allows you to provide a fixed set of UUIDs before running your test by calling setGeneratedUuids(). I have modified the API of the MockUuidSequenceGenerator to make this possible.
    • Add a saga example, point to some references.
    • Add a comment about the service tag.

    Looking forward to your feedback!

    opened by matthiasnoback 18
  • Stream type

    Stream type

    This is a start to add the stream type (in most cases the Aggregate Root) to the EventStore.

    Still TODO:

    • [ ] Check if we need to normalize the classname
    • [x] Update CHANGELOG
    • [ ] Give some hints/snippets to add a migration to your application
    • [x] Provide a more sensible name, I don't really like stream type here
    opened by wjzijderveld 17
  • Elastic search and findBy fields

    Elastic search and findBy fields

    Hi,

    I was searching via findBy method https://github.com/qandidate-labs/broadway/blob/41a495d69fba2303622febfb3bc715a0f500c61d/src/Broadway/ReadModel/ElasticSearch/ElasticSearchRepository.php#L91 and was not getting any results.

    $fields = [
        'name' => 'beta',
    ];
    $this->repository->findBy($fields)
    

    I tried with plain elastic search api and results are getting for below api .

    <?php
    $searchParams = array();
    $searchParams['index'] = 'something';
    $searchParams['type']  = 'Some\Namespaced\Class';
    $searchParams['body']['query']['wildcard']['name'] = 'b*';
    // $searchParams['body']['query']['match']['name'] = 'beta';
    

    The find with id is working as expected.

    Thanks!

    opened by harikt 17
  • Problem when trying to use DBALEventStore with PostgreSQL

    Problem when trying to use DBALEventStore with PostgreSQL

    This is a little strange, and it's likely an issue with how I'm using Doctrine DBAL. But, other users of this library may run into this issue, and it would be helpful if there's an answer here.

    Everything works just fine if I use pdo_sqlite. The problem comes in when using the pdo_pgsql driver. There's apparently some column name case-sensitivity issues happening and I cannot figure out the way around it. Granted, I'm new to working directly with DBAL, but still... nothing I've tried helps.

    I have a test class with the following set up:

    $parameters = [
        'driver'        => 'pdo_pgsql',
        'user'          => 'test',
        'password'      => 'test',
        'database'      => 'test',
        'host'          => 'localhost',
        'port'          => 5433,
    ];
    
    $connection     = DriverManager::getConnection($parameters);
    $schemaManager  = $connection->getSchemaManager();
    $schema         = $schemaManager->createSchema();
    $eventStore     = new DBALEventStore($connection, new SimpleInterfaceSerializer(), new SimpleInterfaceSerializer(), 'events');
    
    if ($table = $eventStore->configureSchema($schema)) {
        $schemaManager->createTable($table);
    }
    

    Yes, 5433 is the correct port on this machine (not the default 5432) and all of the connection info is correct. I can connect to the database.

    Here's the problem:

    When createTable($table) is called, the column names are getting normalized and thus lowercase. This is an issue with the recordedOn field. The column name is getting created as 'recordedon'. This means that the deserializeEvent is throwing an error on

    DateTime::fromString($row['recordedOn'])
    

    because it thinks the recordedOn doesn't exist (which it doesn't the database has it as 'recordedon').

    The inserts into the table work just fine. The data is getting retrieved just fine. It just crashes in the deserializeEvent method.

    If I manually change the column name in the database to recordedOn, then the insert commands in the event store no longer work.

    Broadway\EventStore\DBALEventStoreException:
    
    Caused by
    Doctrine\DBAL\DBALException: An exception occurred while executing 'INSERT INTO events (uuid, playhead, metadata, payload, recordedOn, type) VALUES (?, ?, ?, ?, ?, ?)' with params ["07ebf76f-7ddf-4e57-969d-e271c560ebdd", 0, "{\"class\":\"Broadway\\\\Domain\\\\Metadata\",\"payload\":[]}", "{\"class\":\"Cybernox\\\\Theme\\\\Events\\\\ThemeCreatedEvent\",\"payload\":{\"themeId\":\"07ebf76f-7ddf-4e57-969d-e271c560ebdd\"}}", "2014-09-16T07:07:02.626363+00:00", "Cybernox.Theme.Events.ThemeCreatedEvent"]:
    
    SQLSTATE[42703]: Undefined column: 7 ERROR:  column "recordedon" of relation "events" does not exist
    LINE 1: ...T INTO events (uuid, playhead, metadata, payload, recordedOn...
    

    I thought it might be simply a case of needing to configure the connection to use the PDO::CASE_NATURAL values, so I added a driverOptions to the connection. Still nothing (trying CASE_LOWER and CASE_UPPER didn't work either. In fact, UPPER caused a bigger crash where tables and column names were empty)

    $parameters = [
        'driver'        => 'pdo_pgsql',
        'user'          => 'test',
        'password'      => 'test',
        'database'      => 'test',
        'host'          => 'localhost',
        'port'          => 5433,
        'driverOptions' => [\PDO::ATTR_CASE => \PDO::CASE_NATURAL],
    ];
    

    The only way I could get a success (and it's totally wrong, I was just trying to see if I could get SOMETHING to work), was to add

    $row['recordedOn'] = $row['recordedon'];
    

    to DBALEventStore::deserializeEvent() just to keep the mismatch from happening.

    Anyone know of the proper voodoo to use with the dbal connection to keep the column names as-is instead of getting lowercased?

    opened by mbadolato 16
  • ID can also be an object that implements __toString

    ID can also be an object that implements __toString

    Here is my use case:

        /**
         * @test
         */
        public function it_should_suspend()
        {
            $userId = UserId::generate();
    
            $this->scenario
                ->given([UserWasRegistered::with($userId, new Person)], $userId)
                ->when(SuspendUser::with($userId))
                ->then([
                    UserWasSuspended::with($userId),
                ]);
        }
    

    This is loosely related to #18 in that I ran into both of these problems more or less at the same time. Since my ID is an object I was going to have to do a lot of (string) $id in a lot of weird places and it was becoming unmanageable.

    The issues were mainly around the fact that the InMemoryEventStore were using $id raw and assuming it was a stringish looking thing. I made changes to DBALEventStore to keep it consistent.

    There should be a test to make sure this functionality continues to work but I wanted to make sure I'm on the right track here first. All of my domain models have an actual value object to represent their ID so this is going to be a big deal for me to have to change if I cannot pass the ID as-is in many places.

    opened by simensen 16
  • [RFC] Upcasting

    [RFC] Upcasting

    With this PR I tried to develop my idea up upcasting for the broadway library. It is based on a previous PR, but I have also provided an example of how to use this functionality via a test.

    If the idea is approved, I would like to then work on the DBAL driver and symphony bundle for broadway.

    How it works:

    At the moment, the code works with the InMemoryEventStore class. In order to not touch the original class, I created a decorator for it. Regarding the DBAL driver integration, I could apply the decorator pattern or modify the original DBALEventStore class. What do you think?

    The SequentialUpcasterChain class is a kind of registry used to register individual upcasters, which obviously need to be registered in an orderly manner.

    I could potentially improve the SequentialUpcasterChain class by handling the upcasters' priority during instantiation in order to guarantee and enforce the ordering.

    The example I have provided is based on the UserCreated event, which obviously is a bit of a stretch as it is conceptually an event that would be dispatched only once for each aggregate, but it should give the idea of how the feature works. A more realistic use case could be based on an event like PersonalDataRegistered, which could occur several times.

    opened by matiux 8
Releases(2.4.0)
  • 2.3.0(Mar 6, 2020)

  • 2.1.0(Jan 14, 2019)

    • 412ce18 fixed return type (#369) (Alessandro Minoccheri)
    • 5745145 added php 7.3 on travis file (#368) (Alessandro Minoccheri)
    • ee2fd58 Update examples.md (othillo)
    • 04b93c6 added missing docblock headers (othillo)
    • 3e87591 coding standard fixes (othillo)
    • 597ae55 Add examples for creating read models (#356) (Fritsjan)
    • 1d98f57 Add example of how to replay events using EventStoreManagement and Criteria (#363) (Fritsjan)
    • a7bf429 Query event store example (#360) (Willem-Jan Zijderveld)
    • 4e6b8a3 chore: undo test case as with the current implementation all cases all covered + use finally as it is done in SimpleEventBus (Félix Carpena)
    • 9f3a146 chore: manage throwable exception in order to set isDispatching to false (Félix Carpena)
    • 338ed8a Update beberlei/assert to ~3.0 (Luis Tacón)
    • e17e058 drop instaclick/base-test-bundle (othillo)
    • 1edfdd1 applied coding standards (othillo)
    • 534c57b more specific array type hint annotations (othillo)
    • ffc8ba7 removed superfluous docblocks (othillo)
    • 4c4df45 void return type (othillo)
    • dba8471 added missing type hints (othillo)
    • 164ace7 nullable return types (othillo)
    • 2ee386a require PHP 7.1 (othillo)
    • 75883ac Added read model repository findAll test case (Ettore Delprino)
    • 3b637e2 CR fixes (othillo)
    • 99a2baf linked to other Broadway repositories (othillo)
    • 879f1e4 moved individual component documentation (othillo)
    • 22e0f5f split documentation (othillo)
    • 94e02be removed caution as Broadway is stable (othillo)
    • d172b59 link to documentation (othillo)
    • 8796442 Test PHP 7.2 on Travis CI (#351) (Andrey Bolonin)
    • 8c1a063 enforce license (othillo)
    • 59233ca pass the type of the aggregate instead of the expected type of the repository (othillo)
    • 6c2132f prefer ::class notation (othillo)
    • b636470 remove unnecessary method (othillo)
    • 412ce18 fixed return type (#369) (Alessandro Minoccheri)
    • 5745145 added php 7.3 on travis file (#368) (Alessandro Minoccheri)
    • ee2fd58 Update examples.md (Sander van Thillo)
    • 04b93c6 added missing docblock headers (othillo)
    • 3e87591 coding standard fixes (othillo)
    • 597ae55 Add examples for creating read models (#356) (Fritsjan)
    • 1d98f57 Add example of how to replay events using EventStoreManagement and Criteria (#363) (Fritsjan)
    • a7bf429 Query event store example (#360) (Willem-Jan Zijderveld)
    • 4e6b8a3 chore: undo test case as with the current implementation all cases all covered + use finally as it is done in SimpleEventBus (Félix Carpena)
    • 9f3a146 chore: manage throwable exception in order to set isDispatching to false (Félix Carpena)
    • 338ed8a Update beberlei/assert to ~3.0 (Luis Tacón)
    • e17e058 drop instaclick/base-test-bundle (othillo)
    • 1edfdd1 applied coding standards (othillo)
    • 534c57b more specific array type hint annotations (othillo)
    • ffc8ba7 removed superfluous docblocks (othillo)
    • 4c4df45 void return type (othillo)
    • dba8471 added missing type hints (othillo)
    • 164ace7 nullable return types (othillo)
    • 2ee386a require PHP 7.1 (othillo)
    • 75883ac Added read model repository findAll test case (Ettore Delprino)
    • 3b637e2 CR fixes (othillo)
    • 99a2baf linked to other Broadway repositories (othillo)
    • 879f1e4 moved individual component documentation (othillo)
    • 22e0f5f split documentation (othillo)
    • 94e02be removed caution as Broadway is stable (othillo)
    • d172b59 link to documentation (othillo)
    • 8796442 Test PHP 7.2 on Travis CI (#351) (Andrey Bolonin)
    • 8c1a063 enforce license (othillo)
    • 59233ca pass the type of the aggregate instead of the expected type of the repository (othillo)
    • 6c2132f prefer ::class notation (othillo)
    • b636470 remove unnecessary method (othillo)
    Source code(tar.gz)
    Source code(zip)
Revolt is a rock-solid event loop for concurrent PHP applications.

Revolt is a rock-solid event loop for concurrent PHP applications.

Revolt PHP 586 Jan 2, 2023
An asynchronous event driven PHP socket framework. Supports HTTP, Websocket, SSL and other custom protocols. PHP>=5.3.

Workerman What is it Workerman is an asynchronous event-driven PHP framework with high performance to build fast and scalable network applications. Wo

walkor 10.2k Jan 4, 2023
Event-driven, non-blocking I/O with PHP.

Event-driven, non-blocking I/O with PHP. ReactPHP is a low-level library for event-driven programming in PHP. At its core is an event loop, on top of

ReactPHP 8.5k Jan 8, 2023
Événement is a very simple event dispatching library for PHP.

Événement Événement is a very simple event dispatching library for PHP. It has the same design goals as Silex and Pimple, to empower the user while st

Igor 1.2k Jan 4, 2023
A pragmatic event sourcing library for PHP with a focus on developer experience.

EventSaucePHP EventSauce is a somewhat opinionated, no-nonsense, and easy way to introduce event sourcing into PHP projects. It's designed so storage

EventSauce 685 Dec 31, 2022
[READ-ONLY] The event dispatcher library for CakePHP. This repo is a split of the main code that can be found in https://github.com/cakephp/cakephp

CakePHP Event Library This library emulates several aspects of how events are triggered and managed in popular JavaScript libraries such as jQuery: An

CakePHP 21 Oct 6, 2022
A non-blocking concurrency framework for PHP applications. 🐘

Amp is a non-blocking concurrency framework for PHP. It provides an event loop, promises and streams as a base for asynchronous programming. Promises

Amp 3.8k Jan 6, 2023
Infrastructure and testing helpers for creating CQRS and event sourced applications.

Broadway is a project providing infrastructure and testing helpers for creating CQRS and event sourced applications. Broadway tries hard to not get in your way.

null 1.5k Dec 30, 2022
Orkestra is a library of infrastructure and architecture helpers for creating CQRS applications

Orkestra Orkestra is an opinionated framework with a plethora of recommendations on architectural design that we use internally at Morebec to develop

Morébec 2 Aug 18, 2021
A Laravel artisan based package to create the AWS (SES + SNS) infrastructure to receive email event notifications with Http/Https endpoint.

Laravel SES Tracking Setup the AWS infrastructure to handle email events using SES/SNS and http/s endpoints with a single Laravel artisan command. Thi

null 11 Apr 26, 2022
Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda.

Our Wedding Website Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda. ?

Edd Mann 3 Aug 21, 2022
Ecotone Framework is Service Bus Implementation. It enables message driven architecture and DDD, CQRS, Event Sourcing PHP

This is Read Only Repository To contribute make use of Ecotone-Dev repository. Ecotone is Service Bus Implementation, which enables message driven arc

EcotoneFramework 308 Dec 29, 2022
PHP Application using DDD CQRS Event Sourcing with Hexagonal Architecture

PHP Application using DDD CQRS Event Sourcing with Hexagonal Architecture Application built with Ecotone Framework and powered by integrations with Pr

EcotoneFramework 65 Dec 27, 2022
ReadMarvel's open sourced code

Read Marvel ReadMarvel.com is a fan made website. It is built entirely on Laravel 5. All data is provided by Marvel through their public Marvel API. Y

Ivan Atanasov 32 Jun 7, 2021
A Magento community sourced security pre-flight checklist.

Magento Security Checklist This is a community sourced checklist of security measures to take before launching your store. Think of it as a pre-flight

Talesh Seeparsan 119 Oct 27, 2022
The 1Password Connect PHP SDK provides your PHP applications access to the 1Password Connect API hosted on your infrastructure and leverage the power of 1Password Secrets Automation

1Password Connect PHP SDK The 1Password Connect PHP SDK provides your PHP applications access to the 1Password Connect API hosted on your infrastructu

Michelangelo van Dam 12 Dec 26, 2022
Integration testing helpers for the Slim Framework

Slim Test Helpers Integration testing helpers for the Slim Framework 3 For a full example, please see the companion repo at there4/slim-unit-testing-e

There4 60 Oct 26, 2022
Class helpers for Symfony applications

Micro-Symfony Tools Class helpers for Symfony applications. Installation composer require yceruto/micro-symfony Micro-Bundle Bundles are a very impor

Yonel Ceruto 4 Sep 23, 2022
A video course for laravel artisan to learn creating API using testing

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Bitfumes 16 Oct 6, 2022