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