Skip to content

Commit 141fc51

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

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

service_container/service_decoration.rst

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,4 +313,105 @@ 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+
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+
316417
.. _`Decorator pattern`: https://en.wikipedia.org/wiki/Decorator_pattern

0 commit comments

Comments
 (0)