Как декорировать сервисы

Как декорировать сервисы

При переопределении существующего определения (например, при применении Декоратора (шаблона проектирования)), первоначальный сервис теряется:

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
services:
    app.mailer:
        class: AppBundle\Mailer

    # это заменяет старое определение app.mailer новым,
    # а старое определение теряется
    app.mailer:
        class: AppBundle\DecoratingMailer

В большинстве случаев это будет именно то, что вы будете хотеть сделать. Но иногда, вы можете захотеть вместо этого декорировать старый сервис, и оставить его, чтобы ссылаться а него:

  • YAML
  • XML
  • PHP
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

Опция 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
  • XML
  • PHP
1
2
3
4
5
services:
    app.decorating_mailer:
        # ...
        decoration_inner_name: app.decorating_mailer.wooz
        arguments: ['@app.decorating_mailer.wooz']

Приоритет декорирования

Если вы хотите применить к сервису более одного декоратора, вы можете контролировать их порядок, сконфигурировав приоритет декораций, это может быть любое целое число (декораторы с более высокими приоритетами будут применяться в первую очередь).

  • YAML
  • XML
  • PHP
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']

Сгенерированный код будет следующим:

1
$this->services['foo'] = new Baz(new Bar(new Foo()));