Decoration Of Services With Symfony
Honestly I feel awful and don’t want to do anything, included writing a blog post…
Anyway.. we will see how it will be.
let’s start!
***
Let say we have a component that we can access over dependency injection container and we want to add some new features to the component without touch to existing implementation. We can implement decorator desgin pattern also, because of the exact reason for existence of this pattern. But why don’t we do this with Symfony way ?
Symfony provides an easy way to decoration of services.
Let say we have a mail client in our project like the following.
# services.ymlservices:
mailer:
class: AppBundle\Services\Mailler
And… I want to log all reciepents, sender, and subject informations when my application try to send a mail to anywhere. So I decided to decorate my existing mailer implementation.
# services.ymlservices:
mailer:
class: AppBundle\Services\Mailler mailer:
class: AppBundle\Services\Mailer\LoggerDecorator
The last one will replace the first one. But sometimes we need to keep old one instead of replace like that way.
# services.ymlservices:
mailer:
class: AppBundle\Services\Mailler
mailer_logger_decorator:
class: AppBundle\Services\Mailer\LoggerDecorator
decorates: mailer
arguments: ['@mailer_logger_decorator.inner']
public: false
The ‘decorates’ option help us to replace the ‘mailer’ service with ‘mailer_logger_decorator’ service. We marked the decorator service as private in above because of we don’t need to fetch the decorator service directly in anywhere.
Next example, I want to sending mails as asynchronous but still i want to keep my logging feature. Symfony allow to decorate the services with more than one decorator service.You can manage the priority with ‘decoration_priority’ option.
# services.ymlservices:
mailer:
class: AppBundle\Services\Mailler
mailer_logger_decorator:
class: AppBundle\Services\Mailer\LoggerDecorator
decorates: mailer
arguments: ['@mailer_logger_decorator.inner']
public: false
decoration_priority: 1 mailer_queue_decorator:
class: AppBundle\Services\Mailer\QueueDecorator
decorates: mailer
arguments: ['@mailer_queue_decorator.inner']
public: false
decoration_priority: 2
Your declarations will generate the following code.
use AppBundle\Services\Mailer\QueueDecorator;
use AppBundle\Services\Mailer\LoggerDecorator;
use AppBundle\Services\Mailler;$this->services['mailer'] = new LoggerDecorator(new QueueDecorator(new Mailler()));
Enjoy!
References:
http://symfony.com/doc/current/service_container/service_decoration.html