@@ -313,4 +313,105 @@ 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
+ Let's imagine you have a decorator that decorates a service defined in another bundle.
320
+ If for some reasons, that bundle is missing, the ``decoration_on_decorated_invalid ``
321
+ option will allow you to handle the lack of decorated service.
322
+
323
+ .. configuration-block ::
324
+
325
+ .. code-block :: yaml
326
+
327
+ # config/services.yaml
328
+ Foo : ~
329
+
330
+ Bar :
331
+ public : false
332
+ decorates : Foo
333
+ decoration_on_decorated_invalid : ignore
334
+ arguments : ['@Bar.inner']
335
+
336
+ .. code-block :: xml
337
+
338
+ <!-- config/services.xml -->
339
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
340
+
341
+ <container xmlns =" http://symfony.com/schema/dic/services"
342
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
343
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd" >
344
+
345
+ <services >
346
+ <service id =" Foo" />
347
+
348
+ <service id =" Bar" decorates =" Foo" decoration-on-decorated-invalid =" ignore" >
349
+ <argument type =" service" id =" Bar.inner" />
350
+ </service >
351
+ </services >
352
+ </container >
353
+
354
+ .. code-block :: php
355
+
356
+ // config/services.php
357
+ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
358
+
359
+ use Symfony\Component\DependencyInjection\ContainerInterface;
360
+
361
+ return function(ContainerConfigurator $configurator) {
362
+ $services = $configurator->services();
363
+
364
+ $services->set(Foo::class);
365
+
366
+ $services->set(Bar::class)
367
+ ->decorate(Foo::class, null, 0, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)
368
+ ->args([ref(Bar::class.'.inner')]);
369
+
370
+ $services->set(Baz::class)
371
+ ->private()
372
+ ->decorate(Foo::class, null, 1)
373
+ ->args([ref(Baz::class.'.inner')]);
374
+ };
375
+
376
+ Three different behaviors are available:
377
+
378
+ * ``exception ``: The default behavior. When used, a ``ServiceNotFoundException ``
379
+ will be thrown telling that decorator's dependency is missing.
380
+ * ``ignored ``: Using that behavior, the container will remove either decorator
381
+ and decorated services.
382
+ * ``nulled ``: When used, the container will keep the decorator
383
+ service and will set the decorated one to `null `.
384
+
385
+ .. tip ::
386
+
387
+ When using ``nulled ``, you may update the decorator's constructor in
388
+ order to make decorated dependency nullable. In this way, you will be able to
389
+ check the presence of decorated service in other methods.
390
+
391
+ .. code-block :: php
392
+
393
+ namespace App\Service;
394
+
395
+ use App\Service\OptionalDecoratedService;
396
+
397
+ class DecoratorService
398
+ {
399
+ private $decorated;
400
+
401
+ - public function __construct(OptionalDecoratedService $decorated)
402
+ + public function __construct(?OptionalDecoratedService $decorated)
403
+ {
404
+ $this->decorated = $decorated;
405
+ }
406
+
407
+ public function tellInterestingStuff(): string
408
+ {
409
+ + if (!$this->decorated) {
410
+ + return 'Just one interesting thing';
411
+ + }
412
+
413
+ return $this->decorated->tellInterestingStuff().' + one more interesting thing';
414
+ }
415
+ }
416
+
316
417
.. _`Decorator pattern` : https://en.wikipedia.org/wiki/Decorator_pattern
0 commit comments