@@ -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
+ .. versionadded :: 4.4
320
+
321
+ The ``decoration_on_invalid `` option has been introduced in Symfony 4.4.
322
+
323
+ When you decorate a service that doesn't exist, the ``decoration_on_invalid ``
324
+ option allows you to choose the behavior to adopt.
325
+
326
+ Three different behaviors are available:
327
+
328
+ * ``exception ``: A ``ServiceNotFoundException `` will be thrown telling that decorator's dependency is missing. (default)
329
+ * ``ignore ``: The container will remove the decorator.
330
+ * ``null ``: The container will keep the decorator service and will set the decorated one to ``null ``.
331
+
332
+ .. configuration-block ::
333
+
334
+ .. code-block :: yaml
335
+
336
+ # config/services.yaml
337
+ Foo : ~
338
+
339
+ Bar :
340
+ decorates : Foo
341
+ decoration_on_invalid : ignore
342
+ arguments : ['@Bar.inner']
343
+
344
+ .. code-block :: xml
345
+
346
+ <!-- config/services.xml -->
347
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
348
+
349
+ <container xmlns =" http://symfony.com/schema/dic/services"
350
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
351
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd" >
352
+
353
+ <services >
354
+ <service id =" Foo" />
355
+
356
+ <service id =" Bar" decorates =" Foo" decoration-on-invalid =" ignore" >
357
+ <argument type =" service" id =" Bar.inner" />
358
+ </service >
359
+ </services >
360
+ </container >
361
+
362
+ .. code-block :: php
363
+
364
+ // config/services.php
365
+ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
366
+
367
+ use Symfony\Component\DependencyInjection\ContainerInterface;
368
+
369
+ return function(ContainerConfigurator $configurator) {
370
+ $services = $configurator->services();
371
+
372
+ $services->set(Foo::class);
373
+
374
+ $services->set(Bar::class)
375
+ ->decorate(Foo::class, null, 0, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)
376
+ ->args([ref(Bar::class.'.inner')])
377
+ ;
378
+ };
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