@@ -323,17 +323,18 @@ the ``decoration_priority`` option. Its value is an integer that defaults to
323
323
.. code-block :: yaml
324
324
325
325
# config/services.yaml
326
- Foo : ~
326
+ services :
327
+ Foo : ~
327
328
328
- Bar :
329
- decorates : Foo
330
- decoration_priority : 5
331
- arguments : ['@.inner']
329
+ Bar :
330
+ decorates : Foo
331
+ decoration_priority : 5
332
+ arguments : ['@.inner']
332
333
333
- Baz :
334
- decorates : Foo
335
- decoration_priority : 1
336
- arguments : ['@.inner']
334
+ Baz :
335
+ decorates : Foo
336
+ decoration_priority : 1
337
+ arguments : ['@.inner']
337
338
338
339
.. code-block :: xml
339
340
@@ -365,14 +366,14 @@ the ``decoration_priority`` option. Its value is an integer that defaults to
365
366
return function(ContainerConfigurator $configurator) {
366
367
$services = $configurator->services();
367
368
368
- $services->set(Foo::class);
369
+ $services->set(\ Foo::class);
369
370
370
- $services->set(Bar::class)
371
- ->decorate(Foo::class, null, 5)
371
+ $services->set(\ Bar::class)
372
+ ->decorate(\ Foo::class, null, 5)
372
373
->args([service('.inner')]);
373
374
374
- $services->set(Baz::class)
375
- ->decorate(Foo::class, null, 1)
375
+ $services->set(\ Baz::class)
376
+ ->decorate(\ Foo::class, null, 1)
376
377
->args([service('.inner')]);
377
378
};
378
379
@@ -381,6 +382,226 @@ The generated code will be the following::
381
382
382
383
$this->services[Foo::class] = new Baz(new Bar(new Foo()));
383
384
385
+ Stacking Decorators
386
+ -------------------
387
+
388
+ An alternative to using decoration priorities is to create a ``stack `` of
389
+ ordered services, each one decorating the next:
390
+
391
+ .. configuration-block ::
392
+
393
+ .. code-block :: yaml
394
+
395
+ # config/services.yaml
396
+ services :
397
+ decorated_foo_stack :
398
+ stack :
399
+ - class : Baz
400
+ arguments : ['@.inner']
401
+ - class : Bar
402
+ arguments : ['@.inner']
403
+ - class : Foo
404
+
405
+ # using the short syntax:
406
+ decorated_foo_stack :
407
+ stack :
408
+ - Baz : ['@.inner']
409
+ - Bar : ['@.inner']
410
+ - Foo : ~
411
+
412
+ # can be simplified when autowiring is enabled:
413
+ decorated_foo_stack :
414
+ stack :
415
+ - Baz : ~
416
+ - Bar : ~
417
+ - Foo : ~
418
+
419
+ .. code-block :: xml
420
+
421
+ <!-- config/services.xml -->
422
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
423
+ <container xmlns =" http://symfony.com/schema/dic/services"
424
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
425
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
426
+ https://symfony.com/schema/dic/services/services-1.0.xsd"
427
+ >
428
+ <services >
429
+ <stack id =" decorated_foo_stack" >
430
+ <service class =" Baz" >
431
+ <argument type =" service" id =" .inner" />
432
+ </service >
433
+ <service class =" Bar" >
434
+ <argument type =" service" id =" .inner" />
435
+ </service >
436
+ <service class =" Foo" />
437
+ </stack >
438
+
439
+ <!-- can be simplified when autowiring is enabled: -->
440
+ <stack id =" decorated_foo_stack" >
441
+ <service class =" Baz" />
442
+ <service class =" Bar" />
443
+ <service class =" Foo" />
444
+ </stack >
445
+ </services >
446
+ </container >
447
+
448
+ .. code-block :: php
449
+
450
+ // config/services.php
451
+ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
452
+
453
+ return function(ContainerConfigurator $container) {
454
+ $container->services()
455
+ ->stack('decorated_foo_stack', [
456
+ inline_service(\Baz::class)->args([service('.inner')]),
457
+ inline_service(\Bar::class)->args([service('.inner')]),
458
+ inline_service(\Foo::class),
459
+ ])
460
+
461
+ // can be simplified when autowiring is enabled:
462
+ ->stack('decorated_foo_stack', [
463
+ inline_service(\Baz::class),
464
+ inline_service(\Bar::class),
465
+ inline_service(\Foo::class),
466
+ ])
467
+ ;
468
+ };
469
+
470
+ The result will be the same as in the previous section::
471
+
472
+ $this->services['decorated_foo_stack'] = new Baz(new Bar(new Foo()));
473
+
474
+ Like aliases, a ``stack `` can only use ``public `` and ``deprecated `` attributes.
475
+
476
+ Each frame of the ``stack `` can be either an inlined service, a reference or a
477
+ child definition.
478
+ The latter allows embedding ``stack `` definitions into each others, here's an
479
+ advanced example of composition:
480
+
481
+ .. configuration-block ::
482
+
483
+ .. code-block :: yaml
484
+
485
+ # config/services.yaml
486
+ services :
487
+ some_decorator :
488
+ class : App\Decorator
489
+
490
+ embedded_stack :
491
+ stack :
492
+ - alias : some_decorator
493
+ - App\Decorated : ~
494
+
495
+ decorated_foo_stack :
496
+ stack :
497
+ - parent : embedded_stack
498
+ - Baz : ~
499
+ - Bar : ~
500
+ - Foo : ~
501
+
502
+ .. code-block :: xml
503
+
504
+ <!-- config/services.xml -->
505
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
506
+ <container xmlns =" http://symfony.com/schema/dic/services"
507
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
508
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
509
+ https://symfony.com/schema/dic/services/services-1.0.xsd"
510
+ >
511
+ <services >
512
+ <service id =" some_decorator" class =" App\Decorator" />
513
+
514
+ <stack id =" embedded_stack" >
515
+ <service alias =" some_decorator" />
516
+ <service class =" App\Decorated" />
517
+ </stack >
518
+
519
+ <stack id =" decorated_foo_stack" >
520
+ <service parent =" embedded_stack" />
521
+ <service class =" Baz" />
522
+ <service class =" Bar" />
523
+ <service class =" Foo" />
524
+ </stack >
525
+ </services >
526
+ </container >
527
+
528
+ .. code-block :: php
529
+
530
+ // config/services.php
531
+ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
532
+
533
+ use App\Decorated;
534
+ use App\Decorator;
535
+
536
+ return function(ContainerConfigurator $container) {
537
+ $container->services()
538
+ ->set('some_decorator', Decorator::class)
539
+
540
+ ->stack('embedded_stack', [
541
+ service('some_decorator'),
542
+ inline_service(Decorated::class),
543
+ ])
544
+
545
+ ->stack('decorated_foo_stack', [
546
+ inline_service()->parent('embedded_stack'),
547
+ inline_service(\Baz::class),
548
+ inline_service(\Bar::class),
549
+ inline_service(\Foo::class),
550
+ ])
551
+ ;
552
+ };
553
+
554
+ The result will be::
555
+
556
+ $this->services['decorated_foo_stack'] = new App\Decorator(new App\Decorated(new Baz(new Bar(new Foo()))));
557
+
558
+ .. note ::
559
+
560
+ To change existing stacks (i.e. from a compiler pass), you can access each
561
+ frame by its generated id with the following structure:
562
+ ``.stack_id.frame_key ``.
563
+ From the example above, ``.decorated_foo_stack.1 `` would be a reference to
564
+ the inlined ``Baz `` service and ``.decorated_foo_stack.0 `` to the embedded
565
+ stack.
566
+ To get more explicit ids, you can give a name to each frame:
567
+
568
+ .. configuration-block ::
569
+
570
+ .. code-block :: yaml
571
+
572
+ # ...
573
+ decorated_foo_stack :
574
+ stack :
575
+ first :
576
+ parent : embedded_stack
577
+ second :
578
+ Baz : ~
579
+ # ...
580
+
581
+ .. code-block :: xml
582
+
583
+ <!-- ... -->
584
+ <stack id =" decorated_foo_stack" >
585
+ <service id =" first" parent =" embedded_stack" />
586
+ <service id =" second" class =" Baz" />
587
+ <!-- ... -->
588
+ </stack >
589
+
590
+ .. code-block :: php
591
+
592
+ // ...
593
+ ->stack('decorated_foo_stack', [
594
+ 'first' => inline_service()->parent('embedded_stack'),
595
+ 'second' => inline_service(\Baz::class),
596
+ // ...
597
+ ])
598
+
599
+ The ``Baz `` frame id will now be ``.decorated_foo_stack.second ``.
600
+
601
+ .. versionadded :: 5.1
602
+
603
+ The ability to define ``stack `` was introduced in Symfony 5.1.
604
+
384
605
Control the Behavior When the Decorated Service Does Not Exist
385
606
--------------------------------------------------------------
386
607
0 commit comments