Decoupling Logic Through Custom Events in Symfony

Nikolay Nikolov
ITNEXT
Published in
3 min readFeb 22, 2024

--

Image by upklyak on Freepik

In software development, decoupling is a crucial concept for creating maintainable, scalable, and testable applications.

Symfony, a popular PHP framework, provides powerful tools for implementing decoupling patterns, one of which is leveraging events. By utilizing Symfony’s event dispatcher component, developers can decouple various parts of their application, allowing for better separation of concerns and flexibility in extending functionality.

In this article, we’ll explore how to decouple logic through events in Symfony, using custom events and event listeners.

Setting Up the Environment

Before diving into code examples, ensure you have Symfony installed and a basic Symfony application set up. If you haven’t already, you can follow the Symfony documentation for installation and project creation.

Creating Custom Events

To decouple logic using events, we first need to define custom events and dispatch them at appropriate points in our application. Let’s start by creating a custom event class.

Event for Process Started

// src/Event/ProcessStartedEvent.php

namespace App\Event;

use Symfony\Contracts\EventDispatcher\Event;

class ProcessStartedEvent extends Event
{
public const NAME = 'process.started';
}

Event for Process Finished

// src/Event/ProcessFinishedEvent.php

namespace App\Event;

use Symfony\Contracts\EventDispatcher\Event;

class ProcessFinishedEvent extends Event
{
public const NAME = 'process.finished';
}

Dispatching Events

Next, we’ll create a class where we initiate a process and dispatch events at the beginning and end of that process.

// src/Service/ProcessService.php

namespace App\Service;

use App\Event\ProcessStartedEvent;
use App\Event\ProcessFinishedEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

readonly class ProcessService
{
public function __construct(
private EventDispatcherInterface $eventDispatcher
){}

public function startProcess(): void
{
// Dispatch event for process start
$this->eventDispatcher->dispatch(new ProcessStartedEvent());

// Logic for performing the process

// Dispatch event for process finish
$this->eventDispatcher->dispatch(new ProcessFinishedEvent());
}
}

Creating Event Listeners

Now, let’s create event listeners that respond to these custom events.

Event Listener for the Process Started Event

// src/EventListener/ProcessStartListener.php

namespace App\EventListener;

use App\Event\ProcessStartedEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

#[AsEventListener]
class ProcessStartListener
{
public function __invoke(ProcessStartedEvent $event): void
{
// Logic to execute when process starts
}
}

Event Listener for the Process Finished Event

// src/EventListener/ProcessFinishListener.php

namespace App\EventListener;

use App\Event\ProcessFinishedEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

#[AsEventListener]
class ProcessFinishListener
{
public function __invoke(ProcessFinishedEvent $event): void
{
// Logic to execute when process finishes
}
}

The #[AsEventListener] attribute is a PHP 8.0 attribute used in Symfony for annotating classes that serve as event listeners. When applied to an event listener class, it indicates to Symfony that the class should be treated as an event listener, simplifying the registration process.

Additionally, when combined with the __invoke method within the class, Symfony automatically associates this method as the callback for handling the dispatched event. This attribute promotes cleaner and more concise event listener definitions, enhancing readability and reducing boilerplate code.

Conclusion

Decoupling logic through events in Symfony provides a flexible and maintainable way to structure your applications.

By creating custom events and event listeners, you can easily extend functionality without tightly coupling different parts of your codebase.
Whether it’s logging, auditing, or triggering additional processes, Symfony’s event dispatcher component empowers developers to build scalable and modular applications.

Start leveraging events in your Symfony projects today for cleaner, more manageable code.

If you enjoyed this, subscribe to my future articles, follow me if you like 🚀

Clap 👏🏻, drop a comment 💬, and share this article with anyone you think would find it valuable.

Thank you for your support!

--

--

Head of Software Development at CONUTI GmbH | 20 years experience | Passionate about clean code, design patterns, and software excellence.