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

Related tags

Testing 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)
SimpleTest is a framework for unit testing, web site testing and mock objects for PHP

SimpleTest SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Installation Downloads All downloads are stored on G

SimpleTest 147 Jun 20, 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
A set of helpful assertions when testing Laravel applications.

Installation composer require amirrezam75/laravel-assertions I was working on a project and in order to test oauth2 redirection, I ended up with somet

Amir Reza Mehrbakhsh 2 Sep 23, 2022
Event driven BDD test framework for PHP

The highly extensible, highly enjoyable, PHP testing framework. Read more at peridot-php.github.io or head over to the wiki. Building PHAR Peridot's p

Peridot 327 Jan 5, 2023
The modern, simple and intuitive PHP unit testing framework.

atoum PHP version atoum version 5.3 -> 5.6 1.x -> 3.x 7.2 -> 8.x 4.x (current) A simple, modern and intuitive unit testing framework for PHP! Just lik

atoum 1.4k Nov 29, 2022
PHP unit testing framework with built in mocks and stubs. Runs in the browser, or via the command line.

Enhance PHP A unit testing framework with mocks and stubs. Built for PHP, in PHP! Quick Start: Just add EnhanceTestFramework.php and you are ready to

Enhance PHP 67 Sep 12, 2022
PHP libraries that makes Selenium WebDriver + PHPUnit functional testing easy and robust

Steward: easy and robust testing with Selenium WebDriver + PHPUnit Steward is a set of libraries made to simplify writing and running robust functiona

LMC s.r.o. 219 Dec 17, 2022
The Phoronix Test Suite is the most comprehensive testing and benchmarking platform

The Phoronix Test Suite is the most comprehensive testing and benchmarking platform available for Linux, Solaris, macOS, Windows, and BSD operating systems.

Phoronix Test Suite 1.9k Jan 7, 2023
CommandHelper - is a very useful thing for quick code testing and more!

CommandHelper CommandHelper - is a very useful thing for quick code testing and more! Examples: Code: require_once('commandhelper.php');

RuvSleep 1 Feb 11, 2022
An effort to make testing PHP code as easy and fun as its JavaScript equivalent

An effort to make testing PHP code as easy and fun as its JavaScript equivalent when using the excellent Jasmine, from which syntax and general usage is shamelessly borrowed.

Johan Stenqvist 24 Apr 22, 2022
Full-stack testing PHP framework

Codeception Modern PHP Testing for everyone Codeception is a modern full-stack testing framework for PHP. Inspired by BDD, it provides an absolutely n

Codeception Testing Framework 4.6k Jan 7, 2023
AST based PHP Mutation Testing Framework

Infection - Mutation Testing framework Please read documentation here: infection.github.io Twitter: @infection_php Discord: https://discord.gg/ZUmyHTJ

Infection - Mutation Testing Framework for PHP 1.8k Jan 2, 2023
:computer: Parallel testing for PHPUnit

ParaTest The objective of ParaTest is to support parallel testing in PHPUnit. Provided you have well-written PHPUnit tests, you can drop paratest in y

null 2k Dec 31, 2022
The PHP Unit Testing framework.

PHPUnit PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks. Installat

Sebastian Bergmann 18.8k Jan 4, 2023
Unit testing tips by examples in PHP

Unit testing tips by examples in PHP Introduction In these times, the benefits of writing unit tests are huge. I think that most of the recently start

Kamil Ruczyński 894 Jan 4, 2023
Few additional testing assertions for Laravel views

Laravel View Test Assertions Few additional assertions for testing Laravel views. Why Laravel has well established and documented way of testing reque

null 13 Jun 12, 2022
Real-world Project to learning about Unit Testing/TDD with Laravel for everybody

KivaNote - a Laravel TDD Sample Project Let me introduce you to KivaNote, a simple real-world application using Laravel to show you how the TDD & Unit

(Seth) Phat Tran 10 Dec 31, 2022
Package for unit testing Laravel form request classes

Package for unit testing Laravel form request classes. Why Colin DeCarlo gave a talk on Laracon online 21 about unit testing Laravel form requests cla

null 18 Dec 11, 2022
Magic Test allows you to write browser tests by simply clicking around on the application being tested, all without the slowness of constantly restarting the testing environment.

Magic Test for Laravel Magic Test allows you to write browser tests by simply clicking around on the application being tested, all without the slownes

null 400 Jan 5, 2023