Skip to content

Commit 5e9a253

Browse files
committed
Add "Handling decorations on non existent service"
1 parent 07fd43a commit 5e9a253

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

service_container/service_decoration.rst

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,4 +313,114 @@ The generated code will be the following::
313313

314314
$this->services[Foo::class] = new Baz(new Bar(new Foo()));
315315

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+
316426
.. _`Decorator pattern`: https://en.wikipedia.org/wiki/Decorator_pattern

0 commit comments

Comments
 (0)