Skip to content

Commit d48ec7c

Browse files
committed
feature #17295 [DependencyInjection] Document stack definitions (HeahDude)
This PR was merged into the 5.4 branch. Discussion ---------- [DependencyInjection] Document `stack` definitions Fixes #13587. Commits ------- 02ae0a5 [DependencyInjection] Document `stack` definitions
2 parents a385ac1 + 02ae0a5 commit d48ec7c

File tree

1 file changed

+235
-14
lines changed

1 file changed

+235
-14
lines changed

service_container/service_decoration.rst

Lines changed: 235 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -258,17 +258,18 @@ the ``decoration_priority`` option. Its value is an integer that defaults to
258258
.. code-block:: yaml
259259
260260
# config/services.yaml
261-
Foo: ~
261+
services:
262+
Foo: ~
262263
263-
Bar:
264-
decorates: Foo
265-
decoration_priority: 5
266-
arguments: ['@.inner']
264+
Bar:
265+
decorates: Foo
266+
decoration_priority: 5
267+
arguments: ['@.inner']
267268
268-
Baz:
269-
decorates: Foo
270-
decoration_priority: 1
271-
arguments: ['@.inner']
269+
Baz:
270+
decorates: Foo
271+
decoration_priority: 1
272+
arguments: ['@.inner']
272273
273274
.. code-block:: xml
274275
@@ -300,14 +301,14 @@ the ``decoration_priority`` option. Its value is an integer that defaults to
300301
return function(ContainerConfigurator $configurator) {
301302
$services = $configurator->services();
302303
303-
$services->set(Foo::class);
304+
$services->set(\Foo::class);
304305
305-
$services->set(Bar::class)
306-
->decorate(Foo::class, null, 5)
306+
$services->set(\Bar::class)
307+
->decorate(\Foo::class, null, 5)
307308
->args([service('.inner')]);
308309
309-
$services->set(Baz::class)
310-
->decorate(Foo::class, null, 1)
310+
$services->set(\Baz::class)
311+
->decorate(\Foo::class, null, 1)
311312
->args([service('.inner')]);
312313
};
313314
@@ -316,6 +317,226 @@ The generated code will be the following::
316317

317318
$this->services[Foo::class] = new Baz(new Bar(new Foo()));
318319

320+
Stacking Decorators
321+
-------------------
322+
323+
An alternative to using decoration priorities is to create a ``stack`` of
324+
ordered services, each one decorating the next:
325+
326+
.. configuration-block::
327+
328+
.. code-block:: yaml
329+
330+
# config/services.yaml
331+
services:
332+
decorated_foo_stack:
333+
stack:
334+
- class: Baz
335+
arguments: ['@.inner']
336+
- class: Bar
337+
arguments: ['@.inner']
338+
- class: Foo
339+
340+
# using the short syntax:
341+
decorated_foo_stack:
342+
stack:
343+
- Baz: ['@.inner']
344+
- Bar: ['@.inner']
345+
- Foo: ~
346+
347+
# can be simplified when autowiring is enabled:
348+
decorated_foo_stack:
349+
stack:
350+
- Baz: ~
351+
- Bar: ~
352+
- Foo: ~
353+
354+
.. code-block:: xml
355+
356+
<!-- config/services.xml -->
357+
<?xml version="1.0" encoding="UTF-8" ?>
358+
<container xmlns="http://symfony.com/schema/dic/services"
359+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
360+
xsi:schemaLocation="http://symfony.com/schema/dic/services
361+
https://symfony.com/schema/dic/services/services-1.0.xsd"
362+
>
363+
<services>
364+
<stack id="decorated_foo_stack">
365+
<service class="Baz">
366+
<argument type="service" id=".inner"/>
367+
</service>
368+
<service class="Bar">
369+
<argument type="service" id=".inner"/>
370+
</service>
371+
<service class="Foo"/>
372+
</stack>
373+
374+
<!-- can be simplified when autowiring is enabled: -->
375+
<stack id="decorated_foo_stack">
376+
<service class="Baz"/>
377+
<service class="Bar"/>
378+
<service class="Foo"/>
379+
</stack>
380+
</services>
381+
</container>
382+
383+
.. code-block:: php
384+
385+
// config/services.php
386+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
387+
388+
return function(ContainerConfigurator $container) {
389+
$container->services()
390+
->stack('decorated_foo_stack', [
391+
inline_service(\Baz::class)->args([service('.inner')]),
392+
inline_service(\Bar::class)->args([service('.inner')]),
393+
inline_service(\Foo::class),
394+
])
395+
396+
// can be simplified when autowiring is enabled:
397+
->stack('decorated_foo_stack', [
398+
inline_service(\Baz::class),
399+
inline_service(\Bar::class),
400+
inline_service(\Foo::class),
401+
])
402+
;
403+
};
404+
405+
The result will be the same as in the previous section::
406+
407+
$this->services['decorated_foo_stack'] = new Baz(new Bar(new Foo()));
408+
409+
Like aliases, a ``stack`` can only use ``public`` and ``deprecated`` attributes.
410+
411+
Each frame of the ``stack`` can be either an inlined service, a reference or a
412+
child definition.
413+
The latter allows embedding ``stack`` definitions into each others, here's an
414+
advanced example of composition:
415+
416+
.. configuration-block::
417+
418+
.. code-block:: yaml
419+
420+
# config/services.yaml
421+
services:
422+
some_decorator:
423+
class: App\Decorator
424+
425+
embedded_stack:
426+
stack:
427+
- alias: some_decorator
428+
- App\Decorated: ~
429+
430+
decorated_foo_stack:
431+
stack:
432+
- parent: embedded_stack
433+
- Baz: ~
434+
- Bar: ~
435+
- Foo: ~
436+
437+
.. code-block:: xml
438+
439+
<!-- config/services.xml -->
440+
<?xml version="1.0" encoding="UTF-8" ?>
441+
<container xmlns="http://symfony.com/schema/dic/services"
442+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
443+
xsi:schemaLocation="http://symfony.com/schema/dic/services
444+
https://symfony.com/schema/dic/services/services-1.0.xsd"
445+
>
446+
<services>
447+
<service id="some_decorator" class="App\Decorator"/>
448+
449+
<stack id="embedded_stack">
450+
<service alias="some_decorator"/>
451+
<service class="App\Decorated"/>
452+
</stack>
453+
454+
<stack id="decorated_foo_stack">
455+
<service parent="embedded_stack"/>
456+
<service class="Baz"/>
457+
<service class="Bar"/>
458+
<service class="Foo"/>
459+
</stack>
460+
</services>
461+
</container>
462+
463+
.. code-block:: php
464+
465+
// config/services.php
466+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
467+
468+
use App\Decorated;
469+
use App\Decorator;
470+
471+
return function(ContainerConfigurator $container) {
472+
$container->services()
473+
->set('some_decorator', Decorator::class)
474+
475+
->stack('embedded_stack', [
476+
service('some_decorator'),
477+
inline_service(Decorated::class),
478+
])
479+
480+
->stack('decorated_foo_stack', [
481+
inline_service()->parent('embedded_stack'),
482+
inline_service(\Baz::class),
483+
inline_service(\Bar::class),
484+
inline_service(\Foo::class),
485+
])
486+
;
487+
};
488+
489+
The result will be::
490+
491+
$this->services['decorated_foo_stack'] = new App\Decorator(new App\Decorated(new Baz(new Bar(new Foo()))));
492+
493+
.. note::
494+
495+
To change existing stacks (i.e. from a compiler pass), you can access each
496+
frame by its generated id with the following structure:
497+
``.stack_id.frame_key``.
498+
From the example above, ``.decorated_foo_stack.1`` would be a reference to
499+
the inlined ``Baz`` service and ``.decorated_foo_stack.0`` to the embedded
500+
stack.
501+
To get more explicit ids, you can give a name to each frame:
502+
503+
.. configuration-block::
504+
505+
.. code-block:: yaml
506+
507+
# ...
508+
decorated_foo_stack:
509+
stack:
510+
first:
511+
parent: embedded_stack
512+
second:
513+
Baz: ~
514+
# ...
515+
516+
.. code-block:: xml
517+
518+
<!-- ... -->
519+
<stack id="decorated_foo_stack">
520+
<service id="first" parent="embedded_stack"/>
521+
<service id="second" class="Baz"/>
522+
<!-- ... -->
523+
</stack>
524+
525+
.. code-block:: php
526+
527+
// ...
528+
->stack('decorated_foo_stack', [
529+
'first' => inline_service()->parent('embedded_stack'),
530+
'second' => inline_service(\Baz::class),
531+
// ...
532+
])
533+
534+
The ``Baz`` frame id will now be ``.decorated_foo_stack.second``.
535+
536+
.. versionadded:: 5.1
537+
538+
The ability to define ``stack`` was introduced in Symfony 5.1.
539+
319540
Control the Behavior When the Decorated Service Does Not Exist
320541
--------------------------------------------------------------
321542

0 commit comments

Comments
 (0)