@@ -258,17 +258,18 @@ the ``decoration_priority`` option. Its value is an integer that defaults to
258
258
.. code-block :: yaml
259
259
260
260
# config/services.yaml
261
- Foo : ~
261
+ services :
262
+ Foo : ~
262
263
263
- Bar :
264
- decorates : Foo
265
- decoration_priority : 5
266
- arguments : ['@.inner']
264
+ Bar :
265
+ decorates : Foo
266
+ decoration_priority : 5
267
+ arguments : ['@.inner']
267
268
268
- Baz :
269
- decorates : Foo
270
- decoration_priority : 1
271
- arguments : ['@.inner']
269
+ Baz :
270
+ decorates : Foo
271
+ decoration_priority : 1
272
+ arguments : ['@.inner']
272
273
273
274
.. code-block :: xml
274
275
@@ -300,14 +301,14 @@ the ``decoration_priority`` option. Its value is an integer that defaults to
300
301
return function(ContainerConfigurator $configurator) {
301
302
$services = $configurator->services();
302
303
303
- $services->set(Foo::class);
304
+ $services->set(\ Foo::class);
304
305
305
- $services->set(Bar::class)
306
- ->decorate(Foo::class, null, 5)
306
+ $services->set(\ Bar::class)
307
+ ->decorate(\ Foo::class, null, 5)
307
308
->args([service('.inner')]);
308
309
309
- $services->set(Baz::class)
310
- ->decorate(Foo::class, null, 1)
310
+ $services->set(\ Baz::class)
311
+ ->decorate(\ Foo::class, null, 1)
311
312
->args([service('.inner')]);
312
313
};
313
314
@@ -316,6 +317,226 @@ The generated code will be the following::
316
317
317
318
$this->services[Foo::class] = new Baz(new Bar(new Foo()));
318
319
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
+
319
540
Control the Behavior When the Decorated Service Does Not Exist
320
541
--------------------------------------------------------------
321
542
0 commit comments