diff --git a/service_container/service_decoration.rst b/service_container/service_decoration.rst
index 4c7f2ed0158..06f7a0df1ab 100644
--- a/service_container/service_decoration.rst
+++ b/service_container/service_decoration.rst
@@ -258,17 +258,18 @@ the ``decoration_priority`` option. Its value is an integer that defaults to
.. code-block:: yaml
# config/services.yaml
- Foo: ~
+ services:
+ Foo: ~
- Bar:
- decorates: Foo
- decoration_priority: 5
- arguments: ['@.inner']
+ Bar:
+ decorates: Foo
+ decoration_priority: 5
+ arguments: ['@.inner']
- Baz:
- decorates: Foo
- decoration_priority: 1
- arguments: ['@.inner']
+ Baz:
+ decorates: Foo
+ decoration_priority: 1
+ arguments: ['@.inner']
.. code-block:: xml
@@ -300,14 +301,14 @@ the ``decoration_priority`` option. Its value is an integer that defaults to
return function(ContainerConfigurator $configurator) {
$services = $configurator->services();
- $services->set(Foo::class);
+ $services->set(\Foo::class);
- $services->set(Bar::class)
- ->decorate(Foo::class, null, 5)
+ $services->set(\Bar::class)
+ ->decorate(\Foo::class, null, 5)
->args([service('.inner')]);
- $services->set(Baz::class)
- ->decorate(Foo::class, null, 1)
+ $services->set(\Baz::class)
+ ->decorate(\Foo::class, null, 1)
->args([service('.inner')]);
};
@@ -316,6 +317,226 @@ The generated code will be the following::
$this->services[Foo::class] = new Baz(new Bar(new Foo()));
+Stacking Decorators
+-------------------
+
+An alternative to using decoration priorities is to create a ``stack`` of
+ordered services, each one decorating the next:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # config/services.yaml
+ services:
+ decorated_foo_stack:
+ stack:
+ - class: Baz
+ arguments: ['@.inner']
+ - class: Bar
+ arguments: ['@.inner']
+ - class: Foo
+
+ # using the short syntax:
+ decorated_foo_stack:
+ stack:
+ - Baz: ['@.inner']
+ - Bar: ['@.inner']
+ - Foo: ~
+
+ # can be simplified when autowiring is enabled:
+ decorated_foo_stack:
+ stack:
+ - Baz: ~
+ - Bar: ~
+ - Foo: ~
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ // config/services.php
+ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+
+ return function(ContainerConfigurator $container) {
+ $container->services()
+ ->stack('decorated_foo_stack', [
+ inline_service(\Baz::class)->args([service('.inner')]),
+ inline_service(\Bar::class)->args([service('.inner')]),
+ inline_service(\Foo::class),
+ ])
+
+ // can be simplified when autowiring is enabled:
+ ->stack('decorated_foo_stack', [
+ inline_service(\Baz::class),
+ inline_service(\Bar::class),
+ inline_service(\Foo::class),
+ ])
+ ;
+ };
+
+The result will be the same as in the previous section::
+
+ $this->services['decorated_foo_stack'] = new Baz(new Bar(new Foo()));
+
+Like aliases, a ``stack`` can only use ``public`` and ``deprecated`` attributes.
+
+Each frame of the ``stack`` can be either an inlined service, a reference or a
+child definition.
+The latter allows embedding ``stack`` definitions into each others, here's an
+advanced example of composition:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # config/services.yaml
+ services:
+ some_decorator:
+ class: App\Decorator
+
+ embedded_stack:
+ stack:
+ - alias: some_decorator
+ - App\Decorated: ~
+
+ decorated_foo_stack:
+ stack:
+ - parent: embedded_stack
+ - Baz: ~
+ - Bar: ~
+ - Foo: ~
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ // config/services.php
+ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
+
+ use App\Decorated;
+ use App\Decorator;
+
+ return function(ContainerConfigurator $container) {
+ $container->services()
+ ->set('some_decorator', Decorator::class)
+
+ ->stack('embedded_stack', [
+ service('some_decorator'),
+ inline_service(Decorated::class),
+ ])
+
+ ->stack('decorated_foo_stack', [
+ inline_service()->parent('embedded_stack'),
+ inline_service(\Baz::class),
+ inline_service(\Bar::class),
+ inline_service(\Foo::class),
+ ])
+ ;
+ };
+
+The result will be::
+
+ $this->services['decorated_foo_stack'] = new App\Decorator(new App\Decorated(new Baz(new Bar(new Foo()))));
+
+.. note::
+
+ To change existing stacks (i.e. from a compiler pass), you can access each
+ frame by its generated id with the following structure:
+ ``.stack_id.frame_key``.
+ From the example above, ``.decorated_foo_stack.1`` would be a reference to
+ the inlined ``Baz`` service and ``.decorated_foo_stack.0`` to the embedded
+ stack.
+ To get more explicit ids, you can give a name to each frame:
+
+ .. configuration-block::
+
+ .. code-block:: yaml
+
+ # ...
+ decorated_foo_stack:
+ stack:
+ first:
+ parent: embedded_stack
+ second:
+ Baz: ~
+ # ...
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ // ...
+ ->stack('decorated_foo_stack', [
+ 'first' => inline_service()->parent('embedded_stack'),
+ 'second' => inline_service(\Baz::class),
+ // ...
+ ])
+
+ The ``Baz`` frame id will now be ``.decorated_foo_stack.second``.
+
+.. versionadded:: 5.1
+
+ The ability to define ``stack`` was introduced in Symfony 5.1.
+
Control the Behavior When the Decorated Service Does Not Exist
--------------------------------------------------------------