SmallEventsBundle

From small iceberg
Jump to navigation Jump to search

Target

SmallEventsBundle is a symfony bundle to share events accross symfony apps

Concept

We have 3 symfony apps :

  • ElasticIndexingApp
  • MailApp
  • OrderApp

The OrderApp validate an order. When it's done, an event is emmited.

The ElasticIndexingApp receive the event and reindex disponibility of products.

The MailApp want to notify customer the his order is validated. Then, he handle the event and send the mail.

Here is a small scheme to explain the process : Small-events-principle.png

Repository

The source code is available on githut : https://github.com/sebk69/SebkSmallEventsBundle

Installation

This bundle require :

  • Php >= 7.0
  • Php extensions : bcmath, sockets
  • An installation of Symfony 5
  • composer

In order to send messages, you'll need a RabbitMQ server. Get it at https://www.rabbitmq.com or, if you use docker, at https://hub.docker.com/_/rabbitmq/.

At the root of your symfony project, type :

composer require sebk/small-events-bundle dev-master

Register bundle in config/bundles.php :

<?php

return [
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
    Sebk\SmallEventsBundle\SebkSmallEventsBundle::class => ['all' => true],
];

Configuration

Create a file config/packages/small-events.yml :

sebk_small_events_bundle:
  application_id: tuto-1
  rabbitmq_server: '%env(RABBITMQ_SERVER)%'
  rabbitmq_login: '%env(RABBITMQ_LOGIN)%'
  rabbitmq_password: '%env(RABBITMQ_PASSWORD)%'

As we will see later, the application_id parameter is used to name the rabbitmq queue for events messages. It must be unique in your applications ecosystem.

Emit event

Here is a small example of a command that emit an event each 1 minutes :

<?php

namespace App\Command;

use Sebk\SmallEventsBundle\Dispatcher\SmallDispatcher;
use Sebk\SmallEventsBundle\Event\SmallEvent;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class TestCommand extends Command
{
    protected $dispatcher;

    public function __construct(SmallDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;

        parent::__construct();
    }

    public function execute(InputInterface $input, OutputInterface $output)
    {
        while(true) {
            $event = new SmallEvent();
            $event->setEventName("testEvent");
            $event->setData(["id" => 123456]);
            $this->dispatcher->dispatch($event);

            sleep(60);
        }

        return 0;
    }
}

Subscribe to events

To subscribe to an event, you must create a class in namespace App\EventSubscriber as any symfony event subscriber :

<?php

namespace App\EventSubscriber;

use Sebk\SmallEventsBundle\Event\SmallEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class TestSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            "testEvent" => "onTestEvent",
        ];
    }

    public function onTestEvent(SmallEvent $event)
    {
        echo $event->getDateEmitted()->format("Y-m-d H:i:s") . " - console 2 - onTestEvent\n";
    }
}

See "symfony documentation" for more informations

When it's done just use console to handle events from RabbitMq :

$ bin/console sebk:small-events:listen

In production, it is recommended to manage event listeners with process manager like supervisor.