Below you will find pages that utilize the taxonomy term “Events”
Collecting events and the event dispatching command bus
It was quite a ride so far. We have seen commands, command buses, events and event buses. We distilled some more knowledge about them while formulating answers to some interesting questions from readers.
Why you should not dispatch events while handling a command
In a previous post we discussed a sample event (the UserSignedUp
event):
class UserSignedUp implements Event
{
public function name()
{
return 'user_signed_up';
}
public function __construct($userId)
{
$this->userId = $userId;
}
public function userId()
{
return $this->userId;
}
}
An instance of such an event can be handed over to the event bus. It will look for any number of event handlers that
wants to be notified about the event. In the case of the UserSignedUp
event, one of the interested event handlers is
the SendWelcomeMailWhenUserSignedUp
handler:
Some questions about the command bus
So far we’ve had three posts in this series about commands, events and their corresponding buses and handlers:
Now I’d like to take the time to answer some of the very interesting questions that by readers.
The difference between commands and events
Robert asked:
[…], could you possibly explain what are the main differences between a command bus and an even dispatcher?
From commands to events
In the previous posts we looked at commands and the command bus. Commands are simple objects which express a user’s intention to change something. Internally, the command object is handed over to the command bus, which performs the change that has been requested. While it eventually delegates this task to a dedicated command handler, it also takes care of several other things, like wrapping the command execution in a database transaction and protecting the original order of commands.
Decoupling your (event) system
About interface segregation, dependency inversion and package stability
You are creating a nice reusable package. Inside the package you want to use events to allow others to hook into your own code. You look at several event managers that are available. Since you are somewhat familiar with the Symfony EventDispatcher component already, you decide to add it to your package’s composer.json
:
{
"name": "my/package"
"require": {
"symfony/event-dispatcher": "~2.5"
}
}
Your dependency graph now looks like this:
Symfony2: Event subsystems
Recently I realized that some of the problems I encountered in the past could have been easily solved by what I’m about to explain in this post.
The problem: an event listener introduces a circular reference
The problem is: having a complicated graph of service definitions and their dependencies, which causes a ServiceCircularReferenceException
, saying ‘Circular reference detected for service “…”, path: “… -> … -> …”.’ Somewhere in the path of services that form the circle you then find the event_dispatcher
service. For example: event_dispatcher -> your_event_listener -> some_service -> event_dispatcher
.
Symfony2: Add a global option to console commands and generate a PID file
Recently I read the book Signaling PHP by Cal Evans. It’s a short book, yet very affordable and it learned me a couple of things. First of all it explains about how you can “capture” a Ctrl+C
on your long-running command and do some necessary cleanup work before actually terminating the application. In the appendix it also mentioned the interesting concept of a PID file. Such a file is used to store a single process identifier. The file is created by the process itself, to allow other scripts or applications to terminate it. This is especially useful in the context of daemon applications. They can be started by some wrapper script, run in the background, then be monitored and eventually interrupted by an administrator using the SIGINT
signal.
Symfony2: Defining and dispatching custom form events
The Symfony Form Component has an architecture that keeps inspiring me. It supports horizontal and vertical inheritance and it has a solid event system on a very fine-grained level. In this post I would like to explain how you can expand the event system with your own events. As an example., I will create a new event type used for indicating that the bound form is valid.
Using event listeners and event subscribers with forms
As you can read in a Symfony Cookbook article you can already hook into special form events, defined in Symfony\Component\Form\FormEvents
:
Prevent controller execution with annotations and return a custom response
Symfony2 provides multiple ways of blocking, providing or modifying the response. You can:
-
Intercept each request by listening to the
kernel.request
event and set the response directly on the event (which will effectively skip execution of a controller) -
Modify the controller or its arguments by listening to the
kernel.controller
event, then callingsetController
on the event object and modifying the attributes of theRequest
object. -
Change the response rendered by a controller, by listening to the
kernel.response
event.
Symfony2 & JMSSerializerBundle: Vendor MIME types and API versioning
The JMSSerializerBundle has a VersionExclusionStrategy
, which allows you to serialize/deserialize objects for a specific version of your API. You can mark the properties that are available for different versions using the @Since
and @Until
annotations:
use JMS\SerializerBundle\Annotation\Type;
use JMS\SerializerBundle\Annotation\Since;
use JMS\SerializerBundle\Annotation\Until;
class Comment
{
/**
* @Type("DateTime")
* @Since("1.2.0")
*/
private $createdAt;
/**
* @Type("DateTime")
* @Until("2.1.3")
*/
private $updatedAt;
}
The only thing you have to do is tell the serializer which version to use, before you start using it:
Symfony2: Deserializing request content right into controller arguments
Based on the list of most popular search results leading to my blog, using Symfony2 for building some kind of webservice seems to be quite “hot”. It also seems many people are struggling with the question how they should serialize their content to and from XML and/or JSON. Two beautiful bundles are already available for this, FOSRestBundle and JMSSerializerBundle. Both will help you a lot with this issue, by providing transparent conversion between formats for both the request content and the response body. Nevertheless, a few things are missing. For example, I want to really serialize and deserialize objects, for example, when I send a request with a comment (or part of it) like this:
Symfony2: Extending forms globally ("you know, like with CSRF protection")
With Symfony2, many things are managed through dependency injection. Except for forms. Oh, wait, forms can be services too of course! Remember? Any class instance can be a service… Now, as in many other cases, Symfony2’s FrameworkBundle
adds some magic to the Form component by creating services that link several parts of the Form component together. For example, depending on the value of the framework.csrf_protection
parameter in config.yml
file a hidden field “_token” will be added to all forms, site-wide. To create this kind of very general “form extension” in your own project, you need to do just a few things (I am going to use the example of a “Captcha” form extension, but I don’t give a full implementation of this idea).
Symfony2: An alternative to Symfony 1's "routing.load_configuration" event
Symfony 1 had the lovely routing.load_configuration
event. Listening to this event enabled the developer to add some routes dynamically, “on-the-fly”. Plugins used to do this most of the time. I was looking for a way to accomplish the same in Symfony 2. I’ve used the following as a solution.
We are going to listen to the kernel.request
event, but we make sure we get notified in an early stage, so that the router hasn’t done it’s magic yet. Then we quickly add some extra routes to the RouteCollection
.
Symfony2: how to create a custom Response using an event listener
In some cases you want to return a very specific Response
in case the Request
has some properties like a certain response format.
This situation calls for an event listener, which listens to the kernel.request
event. The listener itself should be a service with some special characteristics: it has the tag “kernel.event_listener” and some extra attributes, i.e. the name of the event
to which it listens and the method
of the service that should be called when this event occurs. When you want to return a very specific Response
, you should listen to the kernel.request
event. We want the kernel to call the method onKernelRequest()
, which we will define later.
Symfony2: create a response filter and set extra response headers
Sometimes you need to make changes to the Response object, after it is returned by your controller, but before it is rendered as output to the client (e.g. the browser). You may want to set some extra response headers, or “completely mess up the content” of the response. You can accomplish this by creating an event listener that listens to the kernel.response
event. I give you a sample event listener which changes the Content-Type
header in case the requested format is “json” and the browser’s accepted response format contains “text/html”; in that case, at least in my experience, the browser doesn’t render the JSON string as plain text when the status code is 4xx or 5xx. So in these situations, the event listener changes the “Content-Type” to “text/plain”, to be sure you always get decent output in the browser.