@@ -313,4 +313,114 @@ The generated code will be the following::
313
313
314
314
$this->services[Foo::class] = new Baz(new Bar(new Foo()));
315
315
316
+ Control the Behavior When the Decorated Service Does Not Exist
317
+ --------------------------------------------------------------
318
+
319
+ When you decorate a service that doesn't exist, the ``decoration_on_invalid ``
320
+ option allows you to choose the behavior to adopt.
321
+
322
+ Three different behaviors are available:
323
+
324
+ * ``exception ``: A ``ServiceNotFoundException `` will be thrown telling that decorator's dependency is missing. (default)
325
+ * ``ignore ``: The container will remove the decorator.
326
+ * ``null ``: The container will keep the decorator service and will set the decorated one to ``null ``.
327
+
328
+ .. configuration-block ::
329
+
330
+ .. code-block :: yaml
331
+
332
+ # config/services.yaml
333
+ Foo : ~
334
+
335
+ Bar :
336
+ decorates : Foo
337
+ decoration_on_invalid : ignore
338
+ arguments : ['@Bar.inner']
339
+
340
+ .. code-block :: xml
341
+
342
+ <!-- config/services.xml -->
343
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
344
+
345
+ <container xmlns =" http://symfony.com/schema/dic/services"
346
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
347
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd" >
348
+
349
+ <services >
350
+ <service id =" Foo" />
351
+
352
+ <service id =" Bar" decorates =" Foo" decoration-on-invalid =" ignore" >
353
+ <argument type =" service" id =" Bar.inner" />
354
+ </service >
355
+ </services >
356
+ </container >
357
+
358
+ .. code-block :: php
359
+
360
+ // config/services.php
361
+ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
362
+
363
+ use Symfony\Component\DependencyInjection\ContainerInterface;
364
+
365
+ return function(ContainerConfigurator $configurator) {
366
+ $services = $configurator->services();
367
+
368
+ $services->set(Foo::class);
369
+
370
+ $services->set(Bar::class)
371
+ ->decorate(Foo::class, null, 0, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)
372
+ ->args([ref(Bar::class.'.inner')])
373
+ ;
374
+ };
375
+
376
+ .. versionadded :: 4.4
377
+
378
+ The ``decoration_on_invalid `` option has been introduced in Symfony 4.4.
379
+
380
+ .. caution ::
381
+
382
+ When using ``null ``, you may have to update the decorator constructor in
383
+ order to make decorated dependency nullable.
384
+
385
+ .. configuration-block ::
386
+
387
+ .. code-block :: yaml
388
+
389
+ App\Service\DecoratorService :
390
+ decorates : Acme\OptionalBundle\Service\OptionalService
391
+ decoration_on_invalid : null
392
+ arguments : ['@App\Service\DecoratorService.inner']
393
+
394
+ .. code-block :: php
395
+
396
+ namespace App\Service;
397
+
398
+ use Acme\OptionalBundle\Service\OptionalService;
399
+
400
+ class DecoratorService
401
+ {
402
+ private $decorated;
403
+
404
+ public function __construct(?OptionalService $decorated)
405
+ {
406
+ $this->decorated = $decorated;
407
+ }
408
+
409
+ public function tellInterestingStuff(): string
410
+ {
411
+ if (!$this->decorated) {
412
+ return 'Just one interesting thing';
413
+ }
414
+
415
+ return $this->decorated->tellInterestingStuff().' + one more interesting thing';
416
+ }
417
+ }
418
+
419
+ .. note ::
420
+
421
+ Sometimes, you may want to add a compiler pass that creates service
422
+ definitions on the fly. If you want to decorate such a service,
423
+ be sure that your compiler pass is registered with ``PassConfig::TYPE_BEFORE_OPTIMIZATION ``
424
+ type so that the decoration pass will be able to find the created services.
425
+
316
426
.. _`Decorator pattern` : https://en.wikipedia.org/wiki/Decorator_pattern
0 commit comments