Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork5.2k
Add Service Configurator documentation.#2110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
Uh oh!
There was an error while loading.Please reload this page.
Merged
Changes fromall commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
225 changes: 225 additions & 0 deletionscomponents/dependency_injection/configurators.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
.. index:: | ||
single: Dependency Injection; Service configurators | ||
Configuring Services with a Service Configurator | ||
================================================ | ||
The Service Configurator is a feature of the Dependency Injection Container that | ||
allows you to use a callable to configure a service after its instantiation. | ||
You can specify a method in another service, a PHP function or a static method | ||
in a class. The service instance is passed to the callable, allowing the | ||
configurator to do whatever it needs to configure the service after its | ||
creation. | ||
A Service Configurator can be used, for example, when you a have a service that | ||
requires complex setup based on configuration settings coming from different | ||
sources/services. Using an external configurator, you can maintain the service | ||
implementation clean and decoupled from the other objects that provide the | ||
configuration for the service. | ||
Another interesting use case is when you have multiple objects that share a | ||
common configuration or that should be configured in a similar way at runtime. | ||
For example, suppose you have an application where you send different types of | ||
emails to users. Emails are passed through different formatters that could be | ||
enabled or not depending on some dynamic application settings. You start | ||
defining a ``NewsletterManager`` class like this:: | ||
class NewsletterManager implements EmailFormatterAwareInterface | ||
{ | ||
protected $mailer; | ||
protected $enabledFormatters; | ||
public function setMailer(Mailer $mailer) | ||
{ | ||
$this->mailer = $mailer; | ||
} | ||
public function setEnabledFormatters(array $enabledFormatters) | ||
{ | ||
$this->enabledFormatters = $enabledFormatters; | ||
} | ||
// ... | ||
} | ||
and also a ``GreetingCardManager`` class:: | ||
class GreetingCardManager implements EmailFormatterAwareInterface | ||
{ | ||
protected $mailer; | ||
protected $enabledFormatters; | ||
public function setMailer(Mailer $mailer) | ||
{ | ||
$this->mailer = $mailer; | ||
} | ||
public function setEnabledFormatters(array $enabledFormatters) | ||
{ | ||
$this->enabledFormatters = $enabledFormatters; | ||
} | ||
// ... | ||
} | ||
As commented before, the formatters should be set at runtime depending on | ||
application settings, so we also have a ``EmailFormatterManager`` class which is | ||
responsible for loading and validating formatters enabled in the application:: | ||
class EmailFormatterManager | ||
{ | ||
protected $enabledFormatters; | ||
public function loadFormatters() | ||
{ | ||
// ... | ||
} | ||
public function getEnabledFormatters() | ||
{ | ||
return $this->enabledFormatters; | ||
} | ||
// ... | ||
} | ||
If your goal is to avoid having to couple ``NewsletterManager`` and | ||
``GreetingCardManager`` with ``EmailFormatterManager``, then you might want to | ||
create a configurator class to configure these instances:: | ||
class EmailConfigurator | ||
{ | ||
private $formatterManager; | ||
public function __construct(EmailFormatterManager $formatterManager) | ||
{ | ||
$this->formatterManager = $formatterManager; | ||
} | ||
public function configure(EmailFormatterAwareInterface $emailManager) | ||
{ | ||
$emailManager->setEnabledFormatters( | ||
$this->formatterManager->getEnabledFormatters() | ||
); | ||
} | ||
// ... | ||
} | ||
``EmailConfigurator`` task is to inject enabled filters to ``NewsletterManager`` | ||
and ``GreetingCardManager`` because they are not aware of where the enabled | ||
filters come from. In the other hand, the ``EmailFormatterManager`` holds the | ||
knowledge about the enabled formatters and how to load them, keeping the single | ||
responsibility principle. | ||
Configurator Service Config | ||
--------------------------- | ||
The service config for the above classes would look something like this: | ||
.. configuration-block:: | ||
.. code-block:: yaml | ||
parameters: | ||
# ... | ||
newsletter_manager.class: NewsletterManager | ||
greeting_card_manager.class: GreetingCardManager | ||
email_formatter_manager.class: EmailFormatterManager | ||
email_configurator.class: EmailConfigurator | ||
services: | ||
my_mailer: | ||
# ... | ||
email_formatter_manager: | ||
class: "%email_formatter_manager.class%" | ||
# ... | ||
email_configurator: | ||
class: "%email_configurator.class%" | ||
arguments: [@email_formatter_manager] | ||
# ... | ||
newsletter_manager: | ||
class: "%newsletter_manager.class%" | ||
calls: | ||
- [setMailer, [@my_mailer]] | ||
configurator: [@email_configurator, configure] | ||
greeting_card_manager: | ||
class: "%greeting_card_manager.class%" | ||
calls: | ||
- [setMailer, [@my_mailer]] | ||
configurator: [@email_configurator, configure] | ||
.. code-block:: xml | ||
<parameters> | ||
<!-- ... --> | ||
<parameter key="newsletter_manager.class">NewsletterManager</parameter> | ||
<parameter key="greeting_card_manager.class">GreetingCardManager</parameter> | ||
<parameter key="email_formatter_manager.class">EmailFormatterManager</parameter> | ||
<parameter key="email_configurator.class">EmailConfigurator</parameter> | ||
</parameters> | ||
<services> | ||
<service id="my_mailer" ...> | ||
<!-- ... --> | ||
</service> | ||
<service id="email_formatter_manager" class="%email_formatter_manager.class%"> | ||
<!-- ... --> | ||
</service> | ||
<service id="email_configurator" class="%email_configurator.class%"> | ||
<argument type="service" id="email_formatter_manager" /> | ||
<!-- ... --> | ||
</service> | ||
<service id="newsletter_manager" class="%newsletter_manager.class%"> | ||
<call method="setMailer"> | ||
<argument type="service" id="my_mailer" /> | ||
</call> | ||
<configurator service="email_configurator" method="configure" /> | ||
</service> | ||
<service id="greeting_card_manager" class="%greeting_card_manager.class%"> | ||
<call method="setMailer"> | ||
<argument type="service" id="my_mailer" /> | ||
</call> | ||
<configurator service="email_configurator" method="configure" /> | ||
</service> | ||
</services> | ||
.. code-block:: php | ||
use Symfony\Component\DependencyInjection\Definition; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
// ... | ||
$container->setParameter('newsletter_manager.class', 'NewsletterManager'); | ||
$container->setParameter('greeting_card_manager.class', 'GreetingCardManager'); | ||
$container->setParameter('email_formatter_manager.class', 'EmailFormatterManager'); | ||
$container->setParameter('email_configurator.class', 'EmailConfigurator'); | ||
$container->setDefinition('my_mailer', ...); | ||
$container->setDefinition('email_formatter_manager', ...); | ||
$container->setDefinition('email_configurator', ...); | ||
$container->setDefinition('newsletter_manager', new Definition( | ||
'%newsletter_manager.class%' | ||
))->addMethodCall('setMailer', array( | ||
new Reference('my_mailer'), | ||
))->setConfigurator(array( | ||
new Reference('email_configurator'), | ||
'configure', | ||
))); | ||
$container->setDefinition('greeting_card_manager', new Definition( | ||
'%greeting_card_manager.class%' | ||
))->addMethodCall('setMailer', array( | ||
new Reference('my_mailer'), | ||
))->setConfigurator(array( | ||
new Reference('email_configurator'), | ||
'configure', | ||
))); |
1 change: 1 addition & 0 deletionscomponents/dependency_injection/index.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -10,6 +10,7 @@ | ||
compilation | ||
tags | ||
factories | ||
configurators | ||
parentservices | ||
advanced | ||
workflow | ||
1 change: 1 addition & 0 deletionscomponents/map.rst.inc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.