Archive for the 'Software' category

Prooph query bus

published on December 20, 2017.

Continuing on with the Prooph series, I want to take a look at the query bus of the Prooph service bus component. The query bus provides a way to issue a query (not necessarily a database query!) to a query handler. This handler is then responsible to return a result for our query.

Why would we need a query bus in the first place? While some may argue that the query bus is not really required, it can be a nice addition to complete the CQRS idea. Just as we have a single endpoint to handle all of our commands and events, we have a single endpoint that can handle all the queries.

The query bus allows the handler to do whatever it needs to do to return the result, synchronously or asynchronously. This is achieved by having the query bus return a ReactPHP Promise. The query handler itself will be a deferred unit of work, which allows it to promise to the querier that the query will be resolved or rejected sometime in the future.

Every query message we send with the query bus, must be routed to exactly one query handler on the other side. Of course, multiple query messages can be routed to the same handler.

Prooph’s service bus also supports a plugin system which we can use, for example, to have authorization of commands, events, and queries, logging… But more on that in a future blog post.

A quick example

The query message, just as a command or an event, can be pretty much anything — a primitive like a string or an integer, a custom data transfer object, or a class implementing the Prooph\Common\Messaging\Message interface by extending the Query class from the prooph-common library.

Setting up the query bus for using it is similar to setting up the command bus or the event bus:

  • we create the query bus,
  • we create a query router that the query bus uses to route query messages to query handlers,
  • we route a query message to its query handler,
  • we attach the router to the query bus,
  • and finally, we dispatch the query on the query bus.

Let’s see how it looks like in code:

query-bus.php

<?php declare(strict_types=1);

require_once 'vendor/autoload.php';

use Prooph\ServiceBus\Plugin\Router\QueryRouter;
use Prooph\ServiceBus\QueryBus;

$queryBus = new QueryBus();

$queryRouter = new QueryRouter();

$queryRouter->route('A simple string')
            ->to(new ProophExample\QueryHandler\Primitives());

$queryRouter->attachToMessageBus($queryBus);

$queryBus->dispatch('A simple string')
         ->done(function($result) {
            echo $result . PHP_EOL;
         }, function ($reason) {
            echo $reason . PHP_EOL;
         });

Not much going on but it shows how to set up and use the query bus.

The query handler part of this example looks like this:

src/ProophExample/QueryHandler/Primitives.php

<?php declare(strict_types=1);

namespace ProophExample\QueryHandler;

use React\Promise\Deferred;

class Primitives
{
    public function __invoke(string $query, Deferred $deferred)
    {
        $i = rand(1, 10);

        if ($i % 2 == 0) {
            $deferred->resolve(str_rot13($query));
        } else {
            $deferred->reject("Out of luck");
        }
    }
}

The query handler is an invokable that gets invoked with the string query and a React\Promise\Deferred unit of work, which we use to either resolve or reject the query.

While this example with the primitives gives an overall picture of how to use the query bus, it’s not really useful.

How many open CFPs are on JoindIn?

JoindIn has an open API which we can use to query it about events, like conferences and meetups. I think we can use it to show a better example of the query bus.

We’re going to have a query message that we’ll use to pass the type of the event we’re interested in — all, hot, upcoming, past, cfp — and a query handler that will assemble the URL for the API call and call it with a simple file_get_contents.

The query message for this example looks something like the following:

src/ProophExample/Query/JoindInEvents.php

<?php declare(strict_types=1);
namespace ProophExample\Query;

use Assert\Assertion;

class JoindInEvents
{
    private $type;
    public function __construct(string $type)
    {
        Assertion::choice($type, ['all', 'hot', 'upcoming', 'past', 'cfp']);
        $this->type = $type;
    }

    public function type(): string
    {
        return $this->type;
    }
}

We pass it in a string $type, assert that it is one of the expected values and set it as a class property. Really not much else to it than that.

The query handler will handle that query, issue the API call and resolve the React promise if it manages to decode the JSON response, or reject it if it fails:

src/ProophExample/QueryHandler/JoindInEvents.php

<?php declare(strict_types=1);

namespace ProophExample\QueryHandler;

use ProophExample\Query\JoindInEvents as Query;
use React\Promise\Deferred;

class JoindInEvents
{
    public function __invoke(Query $query, Deferred $deferred)
    {
        $url = 'https://api.joind.in/v2.1/events';

        $eventType = $query->type();

        if ($eventType != 'all') {
            $url .= '?filter=' . $eventType;
        }

        $response = file_get_contents($url);

        $jsonResponse = json_decode($response);

        if ($jsonResponse === null) {
            $deferred->reject("Error decoding json: " . json_last_error_msg());
        }

        $deferred->resolve($jsonResponse);
    }
}

In a real production code we’d probably use a proper HTTP client instead of file_get_contents, do more error checking and stuff, but in only a few lines of code we can see how to create a query handler.

To put it all together and call it, we’d have something like the following example:

query-bus.php

<?php declare(strict_types=1);

require_once 'vendor/autoload.php';

use Prooph\ServiceBus\Plugin\Router\QueryRouter;
use Prooph\ServiceBus\QueryBus;

$queryBus = new QueryBus();

$queryRouter = new QueryRouter();

$queryRouter->route(ProophExample\Query\JoindInEvents::class)
            ->to(new ProophExample\QueryHandler\JoindInEvents());

$queryRouter->attachToMessageBus($queryBus);

$queryBus->dispatch(new ProophExample\Query\JoindInEvents('cfp'))
         ->done(function($result) {
            echo sprintf("There are %d CFPs!", $result->meta->count) . PHP_EOL;
         }, function($reason){
            echo $reason . PHP_EOL;
         });

If the query message was resolved by the query handler we print out how many CFPs are there right now, and if the query handler rejected the query message, we print out the reason of rejection.

As with the command and the event bus, the examples seen here are available in my prooph-examples repository.

Happy hackin’!

P.S.: Thanks to Alexander Miertsch for helping me understand the query bus a little more!

Mockery return values based on arguments

published on December 12, 2017.

Sometimes when working with Mockery mock objects, we want to tell a mocked method to return different values for different arguments. It is a rare occasion when I need this feature, but every time I need it, I’m happy it’s there.

The feature that allows us to return different values based on arguments is the andReturnUsing Mockery method, which takes a closure as an argument:

example.php

$dependencyMock = \Mockery::mock('SomeDependency');
$dependencyMock->shouldReceive('callDependency')
    ->andReturnUsing(function ($argument) {
        if ($argument <= 10) {
            return 'low';
        }

        return 'high';
    });

$dependencyMock->callDependency(10); // 'low'
$dependencyMock->callDependency(11); // 'high'

Any number of times we call our callDependency method on our mock object with a number 10 or less, it will return 'low', otherwise it will return 'high'.

Not much of an example, so let’s take a look at one a bit closer to a real world scenario.

Say we’re using Doctrine’s entity manager to get repositories for our entities in a service class:

src/ArticleService.php

<?php

class ArticleService
{
    public function __construct(EntityManager $em)
    {
        $this->articleRepo = $em->getRepository(Entity\Article::class);
        $this->authorRepo = $em->getRepository(Entity\Author::class);
    }
}

Not the best of the codes, but we’ll manage. The entity manager receives two calls to the getRepository method, once for the Article entity, once for the Author entity.

In a test case we could then set up the mocks like so:

tests/ArticleServiceTest.php

<?php

class ArticleServiceTest extends MockeryTestCase
{
    public function setup()
    {
        $this->authorRepositoryMock = \Mockery::mock(AuthorRepository::class);
        $this->articleRepositoryMock = \Mockery::mock(ArticleRepository::class);
        $this->entityManagerMock = \Mockery::mock(EntityManager::class);
    }

    public function testArticleService()
    {
        $repositoryMap = [
            'Entity\Author' => $this->authorRepositoryMock,
            'Entity\Article' => $this->articleRepositoryMock,
        ];
        $this->entityManagerMock->shouldReceive('getRepository')
            ->andReturnUsing(function($argument) use ($repositoryMap) {
                return $repositoryMap[$argument];
            });

        $articleService = new ArticleService($this->entityManagerMock);
    }
}

In the setup method we create the three mock objects that we need and then in the test method we create a $repositoryMap to help us map entities to repositories. The repository map could have been created in the andReturnUsing closure as well.

Now when we instantiate the ArticleService with the mocked entity manager, that mocked entity manager will receive two calls to the getRepository method in the ArticleServices constructor, and it will use the closure defined in andReturnUsing to return the correct repository mock objects.

More than one way to do it

Of course there is another way to achieve the same thing and that’s by using andReturn for the return value expectations, but it’s a bit more to write:

tests/ArticleServiceTest.php

<?php
    public function testArticleService()
    {
        $this->entityManagerMock->shouldReceive('getRepository')
            ->with('Entity\Author')
            ->andReturn($this->authorRepositoryMock);
        $this->entityManagerMock->shouldReceive('getRepository')
            ->with('Entity\Article')
            ->andReturn($this->articleRepositoryMock);

        $articleService = new ArticleService($this->entityManagerMock);
    }

It does the same thing as the previous thing. We might even argue that this second example is even clearer than the first example, sure, for a relatively small argument “map”. But if we need to handle a case with more than just two possible arguments, andReturnUsing can help us in those cases.

Happy hackin’!

P.S.: The proper way to do this actually would be to refactor that ArticleService to not get the two repositories from the entity manager, but to inject them directly instead.

CLI command to whitelist Composer packages

published on December 04, 2017.

James asked this question the other day on Twitter:

#LazyWeb is there a way to do a composer update of everything except a specific package or two? like `composer update --exclude doctrine/orm --exclude doctrine/dbal` or something? I don't want to have to whitelist everything all the time (there's bigger problems ofc)

Given that Composer has no --exclude flag or similar, the only other option is to create a list of packages we allow to be updated, excluding the ones we don’t want to be updated. We need to create a whitelist.

Creating it manually would be a PITA though, especially if there’s a lot of packages to include or exclude.

CLI to the rescue!

composer info | grep -v ^doctrine | sed 's/  \+/:/g' | cut -d: -f1 | paste -sd\ 

Note: There’s a single whitespace after the last backslash \.

This would result in a list of packages in a single line, something like:

beberlei/assert composer/ca-bundle container-interop/container-interop guzzlehttp/guzzle mockery/mockery

Let’s break it down

The composer info command shows information about the installed packages. The output is in the format of:

vendor1/package1      vx.y.z      Package 1 description
vendor1/package2      vx.y.z      Package 2 description
vendor2/package       vx.y.z      Package description

It’s all text so we can work with that.

The next step is to remove the packages we don’t want to be in our whitelist. We do that with grep -v ^package1 — search for and output anything that does not start with package1.

We are only interested in the vendor/package parts of the composer info output as that’s all we’ll need eventually for the composer update command.

When we have text that is formatted in columns, we can use the cut command to split these columns by a delimiter. There is a delimiter in the above output from composer info, but the delimiter is a varying number of whitespaces. That’s not really helpful.

What can we do now? Using sed we can replace those whitespaces to something that’s easier to use as a delimiter in cut, a colon : for example. sed 's/ \+/:/g' searches for two or more consecutive spaces and replaces them with a single : (not really visible, but the / \+/ part has two space characters between / and \).

The output at this point would look something like this:

vendor1/package1:vx.y.z:Package 1 description
vendor1/package2:vx.y.z:Package 2 description
vendor2/package:vx.y.z:Package description

Now we can use the cut command, tell it to use the colon as a delimiter with -d: and to take only the first field with -f1.

Finally, we use the paste command to merge lines together to get the final output. The s option is to merge horizontally and the d\ tells it to join using a single space character (again, it’s not really visible, but there is a single space character after the \ character).

Feel free to convert this one liner to a shell script that takes the package names as arguments so it’s a bit more reusable for future uses :)

Happy hackin’!

Tags: bash, cli, composer, shell.
Categories: Development, Software.

Reacting to promises

published on November 29, 2017.

I was working on the next post of my Prooph service bus series, which includes the usage of ReactPHP promises. Given that I haven’t had the chance to take a closer look at it yet, I decided that this is the right time for it.

ReactPHP has several different components, with the end goal of providing a low-level library for event-driven programming in PHP. The one component I want to talk about today is the promise component, which is a Promises/A implementation for PHP.

What this promise library allows us is a nicer workflow with asynchronous code.

With promises, when we want to execute something asynchronously we defer the work that will be executed asynchronously. The Deferred unit of work will complete sometimes in the future, but we don’t know when. But it does promise that the work will be done, one way or the other.

The Promise is a sort of a placeholder for the result that will eventually be returned from our deferred work. This promise can then either be resolved or rejected by our deferred. When a promise is resolved successfully it has an associated value, and when it is rejected it has an associated reason for the rejection.

We use the then method on the promise to register handlers that will be called when the deferred is resolved or rejected.

To install the React/Promise component, run:

$ composer require react/promise

An example

Let’s say we have some code that does some asynchronous work. Checking the HTTP status code of a bunch of URLs, for example. We could create an invokable class that extends the Deferred:

FetchStatusCodes.php

<?php declare(strict_types=1);

use React\Promise\Deferred;

class FetchStatusCodes extends Deferred
{
    public function __invoke(array $urls)
    {
        $multiHandle = curl_multi_init();

        $handles = $this->getHandlesForUrls($urls, $multiHandle);

        $this->executeMultiHandle($multiHandle);

        $statusCodes = $this->getStatusCodes($handles);

        curl_multi_close($multiHandle);

        $successRate = $this->calculateSuccessRate($statusCodes);

        if ($successRate > 50) {
            $this->resolve($statusCodes);
        } else {
            $this->reject('Success rate too low: ' . $successRate);
        }
    }
}

I’ve left out here a bunch of code that deals with the actual fetching of the status codes, just to keep the “noise” down. The full example is available in this repository.

The important thing here is that we extend React\Promise\Deferred and that at the end we call the resolve() method to resolve this deferred if the success rate is over 50%, or that we call the reject() method if the success rate is below 50%.

The set up of the actual promise and its handlers would look something like this:

promise.php

<?php

$statusCodes = new FetchStatusCodes();
$promise = $statusCodes->promise();

$promise
    ->then(
        function($value) {
            var_dump($value);
        },
        function($reason) {
            echo $reason . PHP_EOL;
        }
    );

$urls = [
    'https://example.com/',
    'https://stackoverflow.com/',
    'https://www.google.com/',
    'https://www.google.com/no-such-url',
    'https://www.google.com:81'
];
$statusCodes($urls);

We create the FetchStatusCodes deferred object and get the promise. We setup the resolve and reject handler callbacks in the then method. They don’t do much for now:

  • the resolve handler dumps the value it got,
  • the reject handler prints out the reason of the rejection.

The output for a resolved promise would be something like this:

$ php promise.php
/home/robert/projects/react-promise-example/promise.php:32:
array(5) {
  'https://example.com/' => int(200)
  'https://stackoverflow.com/' => int(200)
  'https://www.google.rs/' => int(200)
  'https://www.google.com/no-such-url' => int(404)
  'https://www.google.com:81/' => int(0)
}

We’re not done yet!

The example above where we call the then method to set up our resolve/reject handlers, isn’t quite correct. Why?

When we call the then method it actually returns a new Promise. This feature of the Promises/A specification allows us to chain promises together.

On this second promise we can again set up our resolve/reject handlers calling the then method on it, same as we do for our first promise. The resolve handler of the second promise will be called with the return value of either the resolve or the reject handler of the first promise. The reject handler of the second promise will be called when either the resolve or the reject handler of the first promise throws an exception. And the then method of our second promise again returns a new, third promise.

Let’s see if an example makes it a bit more clearer:

promise.php

<?php

$statusCodes = new FetchStatusCodes();
$firstPromise = $statusCodes->promise();

$secondPromise = $firstPromise->then(
    function($statusCodes) {
        $successCodes = array_filter($statusCodes, function ($code) {
            if ($code >= 200 && $code < 300) {
                return true;
            }
            return false;
        });
        return $successCodes;
    },
    function($reason) {
        // handle rejected promise
        // gets called when Deferred gets reject-ed
    }
);

$thirdPromise = $secondPromise->then(
    function ($successCodes) {
        return json_encode($successCodes);
    },
    function ($reason) {
        // handle rejected promise
        // gets called when $firstPromise handlers throw an exception
    }
);

$urls = [
    'https://example.com/',
    'https://stackoverflow.com/',
    'https://www.google.com/',
    'https://www.google.com/no-such-url',
    'https://www.google.com:81'
];
$statusCodes($urls);

When our FetchStatusCodes deferred resolves, it will call the resolve handler of the $firstPromise. In that first resolve handler we get only the successful status codes and return them.

With this return from the resolve handler of the first promise, we “trigger” the resolve handler of the $secondPromise where we can, for example, json_encode our success codes. By returning this JSON string from the resolve handler of the second promise, we again “trigger” the resolve handler of the $thirdPromise, and so on.

Almost done!

When we call then, we make a new promise.

To actually be done with all the promises, we need to call the done method on the last promise in our chain. With done we stop making promises and use the result of our last promise:

promise.php

<?php
$thirdPromise->done(
    function ($jsonString) {
        echo $jsonString . PHP_EOL;
    },
    function ($reason) {
        // handle rejected promise
        // gets called when $secondPromise handlers throw an exception
    }
);

If we’d run the example now, we’d get something like this:

$ php promise.php | json_pp
{
   "https://example.com/" : 200,
   "https://www.google.rs/" : 200,
   "https://stackoverflow.com/" : 200
}

We additionally pipe the output of our example script to json_pp to pretty print the JSON string.

Now we’re done

ReactPHP promises have an ExtendedPromisesInterface that include additional shortcut and utility methods that are not part of the Promise/A specification. Their docs include some more examples, and Cees-Jan Kiewiet looks at examples using the react/dns component, among other things.

When we deal with asynchronous code in PHP, using ReactPHP promises gives us a way to deal with it in a much nicer, saner way.

Happy hackin’!

Prooph event bus

published on November 15, 2017.

Let’s continue with the Prooph components, with another part of the Service Bus: the event bus.

As mentioned in the previous article on the command bus, the Prooph Service Bus has three kinds of buses:

  • the command bus,
  • the event bus,
  • and, the query bus.

The event bus takes one event, and that event is sent to all the event listeners that are listening for that event. If there are no listeners, the event bus will still dispatch the event, but it won’t break the application. Any listeners listening to that event, will receive the event, and then we can do something based on that event — update a database table, send an email, push a notification, etc.

Compare that to the command bus, where we send one command on the command bus, and that command must be handled by a registered handler, otherwise the command bus will throw an exception.

Events are messages of things that happened in our system, and we name them accordingly: UserRegistered, CommentAdded, RssFeedUpdated.

From the nature of the events, and from the naming convention, we can conclude that we can not prevent events, as they have already happened. When we create an account for a user, we send an event of that, but we can’t do anything to the event to prevent the creation of the new user account. We can only react to that event.

When working in a DDD fashion, sending events is a great way to notify other bounded contexts of events that happened in our models.

You’re not required to do CQRS, Event Sourcing, and DDD, to be able to use eventing in your applications. It is possible to use the event bus as a standalone component, and if all what you need is to send an event, and then react to that event, do just that. At the very least, you get to decouple the sending of welcome emails, from the actual user registration.

A quick example

The message that represents our event can be anything — a primitive, a custom DTO class, or a class implementing the Message interface from the prooph-common library.

Setting up and using the event bus is similar to setting up and using the command bus:

  • we create the event bus,
  • we create an event router that the event bus uses to route events to event listeners,
  • we route a event to its event listeners,
  • we attach the router to the event bus,
  • and finally, we dispatch the event on the event bus.

Or in code:

event-bus.php

<?php declare(strict_types=1);

require_once 'vendor/autoload.php';

use Prooph\ServiceBus\EventBus;
use Prooph\ServiceBus\Plugin\Router\EventRouter;

$eventBus = new EventBus();

$eventRouter = new EventRouter();

$eventRouter->route('A simple string')
            ->to(new ProophExample\EventListener\Primitives());

$eventRouter->attachToMessageBus($eventBus);

$event = 'A simple string';
$eventBus->dispatch($event);

The Primitives event listener in this case doesn’t do much, and isn’t even named as we would name a real event listener, but it shows how would we create an event listener:

src/ProophExample/EventListener/Primitives.php

<?php declare(strict_types=1);

namespace ProophExample\EventListener;

class Primitives
{
    public function __invoke(string $event)
    {
        echo $event . PHP_EOL;
    }
}

It just outputs the event that it got from the event bus.

Sending a welcome email

A bit more realistic example would be to send a welcome email to a user when they register with us, and to increase the total number of user accounts. Remember, we can have multiple event listeners react to the same event!

We have the UserRegistered event, that will hold the User model that was created during the registration process:

src/ProophExample/Event/UserRegistered.php

<?php declare(strict_types=1);

namespace ProophExample\Event;

use ProophExample\User;

class UserRegistered
{
    /**
    * @var User
    */
    protected $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function user(): User
    {
        return $this->user;
    }
}

We also have the event listener responsible for sending out welcome emails:

src/ProophExample/EventListener/SendWelcomeEmail.php

<?php declare(strict_types=1);

namespace ProophExample\EventListener;

use ProophExample\Event\UserRegistered;

class SendWelcomeEmail
{
    public function __invoke(UserRegistered $event)
    {
        echo sprintf("Hello %s", $event->user()->name()) . PHP_EOL;
    }
}

And we have the event listener responsible for increasing the number of user accounts:

src/ProophExample/EventListener/IncreaseNumberOfAccounts.php

<?php declare(strict_types=1);

namespace ProophExample\EventListener;

use ProophExample\Event\UserRegistered;

class IncreaseNumberOfAccounts
{
    public function __invoke(UserRegistered $event)
    {
        echo "Increasing the number of user accounts" . PHP_EOL;
    }
}

When tying all this together, we’d have something like the following example:

event-bus.php

<?php declare(strict_types=1);

require_once 'vendor/autoload.php';

use Prooph\ServiceBus\EventBus;
use Prooph\ServiceBus\Plugin\Router\EventRouter;

$eventBus = new EventBus();

$eventRouter = new EventRouter();

$eventRouter->route(ProophExample\Event\UserRegistered::class)
            ->to(new ProophExample\EventListener\SendWelcomeEmail())
            ->andTo(new ProophExample\EventListener\IncreaseNumberOfAccounts());

$eventRouter->attachToMessageBus($eventBus);

$user = ProophExample\User::register('john.doe@example.com', 'John Doe');

$event = new ProophExample\Event\UserRegistered($user);

$eventBus->dispatch($event);

We create the event bus, the event router, we route the UserRegistered event to the SendWelcomeEmail event listener, and to the IncreaseNumberOfAccounts event listener, attaching the router to the event bus. Next we register our new user, and we create and dispatch our UserRegistered event.

Running this example gives us:

$ php event-bus.php
Hello John Doe
Increasing the number of user accounts

As we can see, first the event listener responsible for sending the welcome email gets invoked, and then the event listener for increasing the number of user accounts. They were invoked in the order we attached them to the router.

Prooph Messages

In the previous article about the command bus, we saw that the messages, that is the commands, can implement the Prooph\Common\Messaging\Message interface. In that section I said that I don’t really see the benefit of having commands implement that interface, but I do think that the events benefit a great deal from that interface.

Why?

By implementing that interface, we get a UUID for that event, a date and a time when it happened, and other information. All of this is of great value because an event listener might handle an event sometimes in the future, whereas we expect a command to be handled immediately. This extra information about events can be especially useful if/when we want to have Event Sourcing in our application.

An example event that signals that a RSS feed has been updated would look something like this implementing the Message interface:

src/ProophExample/Event/FeedUpdated.php

<?php declare(strict_types=1);

namespace ProophExample\Event;

use Prooph\Common\Messaging\DomainEvent;
use Prooph\Common\Messaging\PayloadConstructable;
use Prooph\Common\Messaging\PayloadTrait;
use ProophExample\Url;

class FeedUpdated extends DomainEvent implements PayloadConstructable
{
    use PayloadTrait;

    public function url(): Url
    {
        return $this->payload['url'];
    }
}

The prooph-common library not only provides the interface, but also abstract classes that help us with implementing the methods defined in the interfaces.

Creating and dispatching this event will then be:

event-bus.php

<?php

$url = ProophExample\Url::fromString('https://robertbasic.com/index.xml');
$event = new ProophExample\Event\FeedUpdated(['url' => $url]);

$eventBus->dispatch($event);

And the listener then can access the Url, as well as the extra event information, like the date and time when the event was created:

src/ProophExample/EventListener/NotifyAboutNewArticles.php

<?php declare(strict_types=1);

namespace ProophExample\EventListener;

use ProophExample\Event\FeedUpdated;

class NotifyAboutNewArticles
{
    public function __invoke(FeedUpdated $event)
    {
        echo sprintf("There are new articles to read from %s since %s",
            $event->url(),
            $event->createdAt()->format('Y-m-d H:i:s')
        ) . PHP_EOL;
    }
}

A more real-world like example

Same as with the command bus, we wouldn’t really use the event bus as we see it in this event-bus.php example file.

We would maybe have a factory of some kind that would create the event bus, configure the event router, and attach it to the event bus. Then we would get the event bus from a psr/container compatible container where we need it, create the event, and then dispatch it on the event bus. I’ve already given an example of this in the previous article, so I don’t want to repeat myself here.

The examples shown and discussed here are available in my prooph-examples repository.

Happy hackin’!

Robert Basic

Robert Basic

Software engineer, consultant, open source contributor.

Let's work together!

If you require outsourcing or consulting help on your projects, I'm available!

Robert Basic © 2008 — 2018
Get the feed