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
Application middlewares are easy to migrate. They are registered by passing a callable to one of the following methods of the Application
instance: before()
, after()
and finish()
. The corresponding kernel events are: kernel.request
, kernel.response
and kernel.terminate
.
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.
Inside a 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.
Inside an 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.
Examples of how application middlewares are migrated can be found in OpenCFP pull requests #871 and #887.
Route Middlewares
Route middlewares are a bit tricky. They are registered by calling before()
and 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 before()
/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.
For an example on how a route middleware is migrated, have a look at OpenCFP pull requests #867 and #888.
Other Event Listeners
The Application
class also offers the methods on()
, error()
and 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.
tl;dr
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.