Как декорировать сервисы¶
При переопределении существующего определения (например, при применении Декоратора (шаблона проектирования)), первоначальный сервис теряется:
- YAML
1 2 3 4 5 6 7 8
services: app.mailer: class: AppBundle\Mailer # это заменяет старое определение app.mailer новым, # а старое определение теряется app.mailer: class: AppBundle\DecoratingMailer
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13
<?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="app.mailer" class="AppBundle\Mailer" /> <!-- это заменяет старое определение app.mailer новым, а старое определение теряется --> <service id="app.mailer" class="AppBundle\DecoratingMailer" /> </services> </container>
- PHP
1 2 3 4 5 6 7 8
use AppBundle\Mailer; use AppBundle\DecoratingMailer; $container->register('app.mailer', Mailer::class); // это заменяет старое определение app.mailer новым, // а старое определение теряется $container->register('app.mailer', DecoratingMailer::class);
В большинстве случаев это будет именно то, что вы будете хотеть сделать. Но иногда, вы можете захотеть вместо этого декорировать старый сервис, и оставить его, чтобы ссылаться а него:
- YAML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
services: app.mailer: class: AppBundle\Mailer app.decorating_mailer: class: AppBundle\DecoratingMailer # переопределяет сервис app.mailer # но этот сервис всё ещё доступен как app.decorating_mailer.inner decorates: app.mailer # передать старый сервис, как аргумент arguments: ['@app.decorating_mailer.inner'] # приватный, так как обычно вам не нужно вызывать app.decorating_mailer напрямую public: false
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
<?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="app.mailer" class="AppBundle\Mailer" /> <service id="app.decorating_mailer" class="AppBundle\DecoratingMailer" decorates="app.mailer" public="false" > <argument type="service" id="app.decorating_mailer.inner" /> </service> </services> </container>
- PHP
1 2 3 4 5 6 7 8 9 10 11
use AppBundle\DecoratingMailer; use AppBundle\Mailer; use Symfony\Component\DependencyInjection\Reference; $container->register('app.mailer', Mailer::class); $container->register('app.decorating_mailer', DecoratingMailer::class) ->setDecoratedService('app.mailer') ->addArgument(new Reference('app.decorating_mailer.inner')) ->setPublic(false) ;
Опция decorates
сообщает контейнеру, что сервис app.decorating_mailer
заменяет
сервис app.mailer
. Старый сервис app.mailer``переименовывается на ``app.decorating_mailer.inner
,
чтобы вы могли внедрить его в ваш новый сервис.
Tip
Видимость (публичная) декорированного сервиса app.mailer
(который явялется
дополнительным именем нового сервиса), будет такой же, как и видимость первоначального
app.mailer
.
Note
Сгенерированный внутрений id осовывается на is сервиса декоратора (тут app.decorating_mailer
),
а не декорированном сервисе (тут app.mailer
). Вы можете контролировать внутренний сервис через
опцию decoration_inner_name
:
- YAML
1 2 3 4 5
services: app.decorating_mailer: # ... decoration_inner_name: app.decorating_mailer.wooz arguments: ['@app.decorating_mailer.wooz']
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
<?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <!-- ... --> <service id="app.decorating_mailer" class="AppBundle\DecoratingMailer" decorates="app.mailer" decoration-inner-name="app.decorating_mailer.wooz" public="false" > <argument type="service" id="app.decorating_mailer.wooz" /> </service> </services> </container>
- PHP
1 2 3 4 5 6 7 8
use AppBundle\DecoratingMailer; use Symfony\Component\DependencyInjection\Reference; $container->register('app.decorating_mailer', DecoratingMailer::class) ->setDecoratedService('app.mailer', 'app.decorating_mailer.wooz') ->addArgument(new Reference('app.decorating_mailer.wooz')) // ... ;
Приоритет декорирования¶
Если вы хотите применить к сервису более одного декоратора, вы можете контролировать их порядок, сконфигурировав приоритет декораций, это может быть любое целое число (декораторы с более высокими приоритетами будут применяться в первую очередь).
- YAML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
foo: class: Foo bar: class: Bar public: false decorates: foo decoration_priority: 5 arguments: ['@bar.inner'] baz: class: Baz public: false decorates: foo decoration_priority: 1 arguments: ['@baz.inner']
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
<?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="foo" class="Foo" /> <service id="bar" class="Bar" decorates="foo" decoration-priority="5" public="false"> <argument type="service" id="bar.inner" /> </service> <service id="baz" class="Baz" decorates="foo" decoration-priority="1" public="false"> <argument type="service" id="baz.inner" /> </service> </services> </container>
- PHP
1 2 3 4 5 6 7 8 9 10 11 12 13
use Symfony\Component\DependencyInjection\Reference; $container->register('foo', 'Foo') $container->register('bar', 'Bar') ->addArgument(new Reference('bar.inner')) ->setPublic(false) ->setDecoratedService('foo', null, 5); $container->register('baz', 'Baz') ->addArgument(new Reference('baz.inner')) ->setPublic(false) ->setDecoratedService('foo', null, 1);
Сгенерированный код будет следующим:
$this->services['foo'] = new Baz(new Bar(new Foo()));
Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.