Skip to content

Commit c0fa50e

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

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

0 commit comments

Comments
 (0)