Migrating Silex Middlewares to Symfony
Silex middlewares are lightweight event listeners that allow developers to run code before or after the request is processed by the controller. Symfony does not have that feature, so before we can migrate our Silex application to Symfony, we need to refactor middlewares into something Symfony understands.
Note: This is part one of a series on articles on migrating Silex applications to Symfony. Other parts:
- Part I: The Silex Sunset
- Part III: Decoupling Silex Applications from the Service Container
Middlewares might be a Silex-only feature, but under the hood, they are executed as event listeners. In fact, Silex even uses the same core events as full-stack Symfony. This is why we can replace middlewares with equivalent event subscribers that will work in Silex and Symfony alike.
Event Listeners vs. Event Subscribers
Silex middlewares just like event listeners in Symfony are simple callables, that are registered for a specific event. Neither the middleware nor the event listener “knows” what event they listen on. That information has to be provided on registration.
Event subscribers on the other hand implement a static method that returns that configuration. In other words, they configure themselves upon registration. When switching over to Symfony, we can directly reuse a subscriber without the need of migrating any configuration for it. This is why I suggest to turn all middlewares into event subscribers.
Application middlewares are easy to migrate. They are registered by passing a callable to one of the following methods of the
finish(). The corresponding kernel events are:
Note that middlewares are only executed on the master request wheras the first two event types are triggered on sub-requests as well. If you don’t want your new subscriber to execute on sub-requests, you specifically need to catch that case.
Silex wraps our middleware before passing it to the event dispatcher. The wrapper maps properties like request and response of the event object to parameters of the middleware. Our new event subscriber will receive the original event object instead.
before middleware, Silex allows us to “short-circuit the request handling” by returning a
Response object. We can achieve the same effect by simply setting the response on the event object instead.
after middleware we can replace the response by returning a new one. An equal event subscriber would again set the response on the event instead.
Route middlewares are a bit tricky. They are registered by calling
after() on a route instead of the
Application instance. Route middlewares are registered on the same events as their application counterparts, but they are only executed if the route they have been registered on was matched! Also, the event priorities are hardcoded for route middlewares.
To simulate that behavior, we can simply replace the
after() call with
value('some_attribute', true). This way, the router will set an attribute
some_attribute on the request. Your event subscriber can check for this attribute to determine whether it should be executed or not. Alternatively, you could as well check the attribute
_route which should contain the name of the matched route.
Other Event Listeners
Application class also offers the methods
view() to register callables as event listeners. The event registration here is pretty straightforward. There is no fancy wrapper logic applied to the callable.
OpenCFP pull request #866 is an example of how an error listener is converted into an event subscriber.
Silex’ middlewares are a handy feature to run code before or after a controller is executed. Symfony does not have that feature, so we refactor middlewares into event subscribers that are compatible with both frameworks.