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