Skip to content

Commit 54b6481

Browse files
wouterjweaverryan
authored andcommitted
Reworded article a bit
1 parent eda26a6 commit 54b6481

File tree

1 file changed

+15
-119
lines changed

1 file changed

+15
-119
lines changed

Diff for: components/dependency_injection/parentservices.rst

+15-119
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,13 @@ would cause an exception to be raised for a non-abstract service.
291291
In order for parent dependencies to resolve, the ``ContainerBuilder`` must
292292
first be compiled. See :doc:`/components/dependency_injection/compilation`
293293
for more details.
294+
295+
.. tip::
296+
297+
In the examples shown, the classes sharing the same configuration also extend
298+
from the same parent in PHP. This does not need to be the case though, you can
299+
extract common parts of similar service definitions into a parent service without
300+
also extending a parent class in PHP.
294301

295302
Overriding Parent Dependencies
296303
------------------------------
@@ -399,123 +406,12 @@ The ``GreetingCardManager`` will receive the same dependencies as before,
399406
but the ``NewsletterManager`` will be passed the ``my_alternative_mailer``
400407
instead of the ``my_mailer`` service.
401408

402-
Collections of Dependencies
403-
---------------------------
404-
405-
It should be noted that the overridden setter method in the previous example
406-
is actually called twice - once per the parent definition and once per the
407-
child definition. In the previous example, that was fine, since the second
408-
``setMailer`` call replaces mailer object set by the first call.
409-
410-
In some cases, however, this can be a problem. For example, if the overridden
411-
method call involves adding something to a collection, then two objects will
412-
be added to that collection. The following shows such a case, if the parent
413-
class looks like this::
414-
415-
abstract class MailManager
416-
{
417-
protected $filters;
418-
419-
public function addFilter($filter)
420-
{
421-
$this->filters[] = $filter;
422-
}
423-
424-
// ...
425-
}
426-
427-
If you had the following config:
428-
429-
.. configuration-block::
430-
431-
.. code-block:: yaml
432-
433-
# ...
434-
services:
435-
my_filter:
436-
# ...
437-
another_filter:
438-
# ...
439-
440-
mail_manager:
441-
abstract: true
442-
calls:
443-
- [addFilter, ["@my_filter"]]
444-
445-
newsletter_manager:
446-
class: "%newsletter_manager.class%"
447-
parent: mail_manager
448-
calls:
449-
- [addFilter, ["@another_filter"]]
450-
451-
.. code-block:: xml
452-
453-
<!-- ... -->
454-
455-
<services>
456-
<service id="my_filter">
457-
<!-- ... -->
458-
</service>
459-
460-
<service id="another_filter">
461-
<!-- ... -->
462-
</service>
463-
464-
<service id="mail_manager" abstract="true">
465-
<call method="addFilter">
466-
<argument type="service" id="my_filter" />
467-
</call>
468-
</service>
469-
470-
<service id="newsletter_manager"
471-
class="%newsletter_manager.class%"
472-
parent="mail_manager"
473-
>
474-
<call method="addFilter">
475-
<argument type="service" id="another_filter" />
476-
</call>
477-
</service>
478-
</services>
479-
480-
.. code-block:: php
481-
482-
use Symfony\Component\DependencyInjection\Definition;
483-
use Symfony\Component\DependencyInjection\DefinitionDecorator;
484-
use Symfony\Component\DependencyInjection\Reference;
485-
486-
// ...
487-
$container->setDefinition('my_filter', ...);
488-
$container->setDefinition('another_filter', ...);
489-
490-
$mailManager = new Definition();
491-
$mailManager
492-
->setAbstract(true)
493-
->addMethodCall('addFilter', array(
494-
new Reference('my_filter'),
495-
))
496-
;
497-
$container->setDefinition('mail_manager', $mailManager);
498-
499-
$newsletterManager = new DefinitionDecorator('mail_manager');
500-
$newsletterManager
501-
->setClass('%newsletter_manager.class%')
502-
->addMethodCall('addFilter', array(
503-
new Reference('another_filter'),
504-
))
505-
;
506-
$container->setDefinition('newsletter_manager', $newsletterManager);
507-
508-
In this example, the ``addFilter`` method of the ``newsletter_manager`` service
509-
will be called twice, resulting in the ``$filters`` array containing both
510-
``my_filter`` and ``another_filter`` objects. This is great if you just want
511-
to add additional filters to the subclasses. If you want to replace the filters
512-
passed to the subclass, removing the parent setting from the config will
513-
prevent the base class from calling ``addFilter``.
514-
515-
.. tip::
409+
.. caution::
516410

517-
In the examples shown there is a similar relationship between the parent
518-
and child services and the underlying parent and child classes. This does
519-
not need to be the case though, you can extract common parts of similar
520-
service definitions into a parent service without also inheriting a parent
521-
class.
411+
You can't override method calls. When you defined new method calls in the child
412+
service, it'll be added to the current set of configured method calls. This means
413+
it works perfectly when the setter overrides the current property, but it doesn't
414+
work as expected when the setter appends it to the existing data (e.g. an
415+
``addFilters()`` method).
416+
In those cases, the only solution is to *not* extend the parent service and configuring
417+
the service just like you did before knowing this feature.

0 commit comments

Comments
 (0)