diff --git a/components/dependency_injection.rst b/components/dependency_injection.rst index af13905456c..7dfa6ef372d 100644 --- a/components/dependency_injection.rst +++ b/components/dependency_injection.rst @@ -288,17 +288,21 @@ config files: .. code-block:: php - use Symfony\Component\DependencyInjection\Reference; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + $configurator->parameters() + ->set('mailer.transport', 'sendmail'); + + $container = $configurator->services(); + + $container->set('mailer', 'Mailer') + ->args(['%mailer.transport%']); + + $container->set('newsletter_manager', 'NewsletterManager') + ->call('setMailer', [ref('mailer')]); + }; - // ... - $container->setParameter('mailer.transport', 'sendmail'); - $container - ->register('mailer', 'Mailer') - ->addArgument('%mailer.transport%'); - - $container - ->register('newsletter_manager', 'NewsletterManager') - ->addMethodCall('setMailer', [new Reference('mailer')]); Learn More ---------- diff --git a/service_container.rst b/service_container.rst index fc5405c1d7e..51ae8ea4125 100644 --- a/service_container.rst +++ b/service_container.rst @@ -182,19 +182,18 @@ each time you ask for it. .. code-block:: php // config/services.php - use Symfony\Component\DependencyInjection\Definition; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - // To use as default template - $definition = new Definition(); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services() + ->defaults() + ->autowire() + ->autoconfigure() + ->private(); - $definition - ->setAutowired(true) - ->setAutoconfigured(true) - ->setPublic(false) - ; - - // $this is a reference to the current loader - $this->registerClasses($definition, 'App\\', '../src/*', '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'); + $container->load('App\\', '../src/*') + ->exclude('../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'); + }; .. tip:: @@ -396,7 +395,7 @@ pass here. No problem! In your configuration, you can explicitly set this argume # same as before App\: resource: '../src/*' - exclude: '../src/{Entity,Migrations,Tests}' + exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' # explicitly configure the service App\Updates\SiteUpdateManager: @@ -416,6 +415,7 @@ pass here. No problem! In your configuration, you can explicitly set this argume + @@ -428,23 +428,23 @@ pass here. No problem! In your configuration, you can explicitly set this argume .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Updates\SiteUpdateManager; - use Symfony\Component\DependencyInjection\Definition; - // Same as before - $definition = new Definition(); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services() + ->defaults() + ->autowire() + ->autoconfigure() + ->private(); - $definition - ->setAutowired(true) - ->setAutoconfigured(true) - ->setPublic(false) - ; + $container->load('App\\', '../src/*') + ->exclude('../src/{Entity,Migrations,Tests}'); - $this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Migrations,Tests}'); + $container->set(SiteUpdateManager::class)->arg('$adminEmail', 'manager@example.com'); + }; - // Explicitly configure the service - $container->getDefinition(SiteUpdateManager::class) - ->setArgument('$adminEmail', 'manager@example.com'); Thanks to this, the container will pass ``manager@example.com`` to the ``$adminEmail`` argument of ``__construct`` when creating the ``SiteUpdateManager`` service. The @@ -503,13 +503,16 @@ parameter and in PHP config use the ``Reference`` class: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Service\MessageGenerator; - use Symfony\Component\DependencyInjection\Reference; - $container->autowire(MessageGenerator::class) - ->setAutoconfigured(true) - ->setPublic(false) - ->setArgument(0, new Reference('logger')); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(MessageGenerator::class) + ->autoconfigure() + ->args([ref('logger')]]); + }; Working with container parameters is straightforward using the container's accessor methods for parameters:: @@ -605,13 +608,18 @@ But, you can control this and pass in a different logger: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Service\MessageGenerator; - use Symfony\Component\DependencyInjection\Reference; - $container->autowire(MessageGenerator::class) - ->setAutoconfigured(true) - ->setPublic(false) - ->setArgument('$logger', new Reference('monolog.logger.request')); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(SiteUpdateManager::class) + ->autowire() + ->autoconfigure() + ->private(); + ->arg('$logger', ref('monolog.logger.request')); + }; This tells the container that the ``$logger`` argument to ``__construct`` should use service whose id is ``monolog.logger.request``. @@ -693,21 +701,22 @@ You can also use the ``bind`` keyword to bind specific arguments by name or type .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Controller\LuckyController; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Reference; - $container->register(LuckyController::class) - ->setPublic(true) - ->setBindings([ - '$adminEmail' => 'manager@example.com', - '$requestLogger' => new Reference('monolog.logger.request'), - LoggerInterface::class => new Reference('monolog.logger.request'), - // optionally you can define both the name and type of the argument to match - 'string $adminEmail' => 'manager@example.com', - LoggerInterface::class.' $requestLogger' => new Reference('monolog.logger.request'), - ]) - ; + return function(ContainerConfigurator $configurator) { + $container = $configurator->services()->defaults() + ->bind('$adminEmail', 'manager@example.com') + ->bind('$requestLogger', ref('monolog.logger.request')) + ->bind(LoggerInterface::class, ref('monolog.logger.request')) + ->bind('string $adminEmail', 'manager@example.com') + ->bind(LoggerInterface::class.' $requestLogger', ref('monolog.logger.request')); + + // ... + }; By putting the ``bind`` key under ``_defaults``, you can specify the value of *any* argument for *any* service defined in this file! You can bind arguments by name @@ -809,6 +818,20 @@ But, if you *do* need to make a service public, override the ``public`` setting: + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use App\Service\MessageGenerator; + + return function(ContainerConfigurator $configurator) { + // ... same as code before + + $container->set(MessageGenerator::class) + ->public(); + }; + .. _service-psr4-loader: Importing Many Services at once with resource @@ -829,7 +852,7 @@ key. For example, the default Symfony configuration contains this: # this creates a service per class whose id is the fully-qualified class name App\: resource: '../src/*' - exclude: '../src/{Entity,Migrations,Tests}' + exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' .. code-block:: xml @@ -850,18 +873,14 @@ key. For example, the default Symfony configuration contains this: .. code-block:: php // config/services.php - use Symfony\Component\DependencyInjection\Definition; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - // To use as default template - $definition = new Definition(); - - $definition - ->setAutowired(true) - ->setAutoconfigured(true) - ->setPublic(false) - ; + return function(ContainerConfigurator $configurator) { + // ... - $this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Migrations,Tests}'); + $container->load('App\\', '../src/*') + ->exclude('../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'); + }; .. tip:: @@ -998,27 +1017,30 @@ admin email. In this case, each needs to have a unique service id: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Service\MessageGenerator; use App\Updates\SiteUpdateManager; - use Symfony\Component\DependencyInjection\Reference; - $container->register('site_update_manager.superadmin', SiteUpdateManager::class) - ->setAutowired(false) - ->setArguments([ - new Reference(MessageGenerator::class), - new Reference('mailer'), - 'superadmin@example.com' - ]); - - $container->register('site_update_manager.normal_users', SiteUpdateManager::class) - ->setAutowired(false) - ->setArguments([ - new Reference(MessageGenerator::class), - new Reference('mailer'), - 'contact@example.com' - ]); - - $container->setAlias(SiteUpdateManager::class, 'site_update_manager.superadmin') + return function(ContainerConfigurator $configurator) { + // ... + + $container->set('site_update_manager.superadmin', SiteUpdateManager::class) + ->autowire(false) + ->args([ + ref(MessageGenerator::class), + ref('mailer'), + 'superadmin@example.com' + ]); + $container->set('site_update_manager.normal_users', SiteUpdateManager::class) + ->autowire(false) + ->args([ + ref(MessageGenerator::class), + ref('mailer'), + 'contact@example.com' + ]); + $container->alias(SiteUpdateManager::class, 'site_update_manager.superadmin'); + }; In this case, *two* services are registered: ``site_update_manager.superadmin`` and ``site_update_manager.normal_users``. Thanks to the alias, if you type-hint diff --git a/service_container/3.3-di-changes.rst b/service_container/3.3-di-changes.rst index b0de1d75d0d..03613a58e1e 100644 --- a/service_container/3.3-di-changes.rst +++ b/service_container/3.3-di-changes.rst @@ -81,9 +81,32 @@ what the file looks like in Symfony 4): + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services() + ->defaults() + ->autowire() + ->autoconfigure() + ->private(); + + $container->load('App\\', '../src/*') + ->exclude('../src/{Entity,Migrations,Tests}'); + + $container->load('App\\Controller\\', '../src/Controller') + ->tag('controller.service_arguments'); + }; + This small bit of configuration contains a paradigm shift of how services are configured in Symfony. +.. versionadded:: 3.4 + + PHP Fluent DI was introduced in Symfony 3.4. + .. _`service-33-changes-automatic-registration`: 1) Services are Loaded Automatically @@ -126,6 +149,18 @@ thanks to the following config: + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + // ... + + $container->load('App\\', '../src/*') + ->exclude('../src/{Entity,Migrations,Tests}'); + }; + This means that every class in ``src/`` is *available* to be used as a service. And thanks to the ``_defaults`` section at the top of the file, all of these services are **autowired** and **private** (i.e. ``public: false``). @@ -319,11 +354,15 @@ The third big change is that, in a new Symfony 3.3 project, your controllers are .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - // ... + return function(ContainerConfigurator $configurator) { + // ... + + $container->load('App\\Controller\\', '../src/Controller') + ->tag('controller.service_arguments'); + }; - $definition->addTag('controller.service_arguments'); - $this->registerClasses($definition, 'App\\Controller\\', '../src/Controller/*'); But, you might not even notice this. First, your controllers *can* still extend the same base controller class (``AbstractController``). @@ -464,6 +503,21 @@ inherited from an abstract definition: + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use App\Domain\LoaderInterface; + + return function(ContainerConfigurator $configurator) { + // ... + + $container->instanceof(LoaderInterface::class + ->public() + ->tag('app.domain_loader'); + }; + What about Performance ---------------------- diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst index c1e9da0e790..4efba8dadfa 100644 --- a/service_container/alias_private.rst +++ b/service_container/alias_private.rst @@ -55,10 +55,15 @@ You can also control the ``public`` option on a service-by-service basis: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Service\Foo; - $container->register(Foo::class) - ->setPublic(false); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(Foo::class) + ->private(); + }; .. _services-why-private: @@ -123,12 +128,16 @@ services. .. code-block:: php // config/services.php - use App\Mail\PhpMailer; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - $container->register(PhpMailer::class) - ->setPublic(false); + use App\Mail\PhpMailer; - $container->setAlias('app.mailer', PhpMailer::class); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(PhpMailer::class) + ->private(); + $container->alias('app.mailer', PhpMailer::class); + }; This means that when using the container directly, you can access the ``PhpMailer`` service by asking for the ``app.mailer`` service like this:: @@ -214,7 +223,15 @@ Anonymous Services .. note:: - Anonymous services are only supported by the XML and YAML configuration formats. + Anonymous services are only supported by the XML, YAML, and PHP Fluent configuration formats. + +.. versionadded:: 3.3 + + The feature to configure anonymous services in YAML was introduced in Symfony 3.3. + +.. versionadded:: 4.1 + + The feaature to configure anonymous services in PHP Fluent was introduced in Symfony 3.4. In some cases, you may want to prevent a service being used as a dependency of other services. This can be achieved by creating an anonymous service. These @@ -252,6 +269,26 @@ The following example shows how to inject an anonymous service into another serv + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use App\Foo; + use App\AnonymousBar; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(Foo::class) + ->args([inline(AnonymousBar::class)]) + }; + +.. note:: + + Anonymous services do *NOT* inherit the definitions provided from the defaults defined in the configuration. So you'll + need to explicitly mark service as autowired or autoconfigured when doing an anonymous service e.g.: `inline(Foo::class)->autowire()->autoconfigure()`. + Using an anonymous service as a factory looks like this: .. configuration-block:: @@ -281,6 +318,21 @@ Using an anonymous service as a factory looks like this: + .. code-block:: php + + // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use App\Foo; + use App\AnonymousBar; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(Foo::class) + ->factory([inline(AnonymousBar::class), 'constructFoo']) + }; + Deprecating Services -------------------- @@ -313,15 +365,16 @@ or you decided not to maintain it anymore), you can deprecate its definition: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Service\OldService; - $container - ->register(OldService::class) - ->setDeprecated( - true, - 'The "%service_id%" service is deprecated since vendor-name/package-name 2.8 and will be removed in 3.0.' - ) - ; + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(OldService::class) + ->deprecate('The "%service_id%" service is deprecated since vendor-name/package-name 2.8 and will be removed in 3.0.'); + }; Now, every time this service is used, a deprecation warning is triggered, advising you to stop or to change your uses of that service. diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst index 19ba0583ffa..bc7fa3fdbb9 100644 --- a/service_container/autowiring.rst +++ b/service_container/autowiring.rst @@ -104,17 +104,19 @@ both services: .. code-block:: php // config/services.php - use App\Service\TwitterClient; - use App\Util\Rot13Transformer; + return function(ContainerConfigurator $configurator) { + $container = $configurator->services() + ->defaults() + ->autowire() + ->autoconfigure() + ->private(); - // ... + $container->set(TwitterClient::class) + ->autowire(); // redundant thanks to defaults, but value is overridable on each service + $container->set(Rot13Transformer::class) + ->autowire(); + }; - // the autowire method is new in Symfony 3.3 - // in earlier versions, use register() and then call setAutowired(true) - $container->autowire(TwitterClient::class); - - $container->autowire(Rot13Transformer::class) - ->setPublic(false); Now, you can use the ``TwitterClient`` service immediately in a controller:: @@ -229,13 +231,19 @@ adding a service alias: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Util\Rot13Transformer; - // ... + return function(ContainerConfigurator $configurator) { + // ... + + $container->set('app.rot13.transformer', Rot13Transformer::class) + ->autowire() + ->private(); + $container->alias(Rot13Transformer::class, 'app.rot13.transformer'); + }; - $container->autowire('app.rot13.transformer', Rot13Transformer::class) - ->setPublic(false); - $container->setAlias(Rot13Transformer::class, 'app.rot13.transformer'); This creates a service "alias", whose id is ``App\Util\Rot13Transformer``. Thanks to this, autowiring sees this and uses it whenever the ``Rot13Transformer`` @@ -329,12 +337,18 @@ To fix that, add an :ref:`alias `: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Util\Rot13Transformer; use App\Util\TransformerInterface; - // ... - $container->autowire(Rot13Transformer::class); - $container->setAlias(TransformerInterface::class, Rot13Transformer::class); + return function(ContainerConfigurator $configurator) { + // ... + + $container->set(Rot13Transformer::class); + $container->alias(TransformerInterface::class, Rot13Transformer::class); + }; + Thanks to the ``App\Util\TransformerInterface`` alias, the autowiring subsystem knows that the ``App\Util\Rot13Transformer`` service should be injected when @@ -459,24 +473,27 @@ the injection:: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Service\MastodonClient; use App\Service\TwitterClient; use App\Util\Rot13Transformer; use App\Util\TransformerInterface; use App\Util\UppercaseTransformer; - // ... - $container->autowire(Rot13Transformer::class); - $container->autowire(UppercaseTransformer::class); - $container->setAlias(TransformerInterface::class, Rot13Transformer::class); - $container->setAlias( - TransformerInterface::class.' $shoutyTransformer', - UppercaseTransformer::class - ); - $container->autowire(TwitterClient::class) - //->setArgument('$transformer', new Reference(UppercaseTransformer::class)) - ; - $container->autowire(MastodonClient::class); + return function(ContainerConfigurator $configurator) { + // ... + + $container->set(Rot13Transformer::class)->autowire(); + $container->set(UppercaseTransformer::class)->autowire(); + $container->alias(TransformerInterface::class.' $shoutyTransformer', UppercaseTransformer::class); + + $container->set(TwitterClient::class) + ->autowire() + // ->arg('$transformer', ref(UppercaseTransformer::class)) + + $container->set(MastodonClient::class)->autowire(); + }; Thanks to the ``App\Util\TransformerInterface`` alias, any argument type-hinted with this interface will be passed the ``App\Util\Rot13Transformer`` service. diff --git a/service_container/calls.rst b/service_container/calls.rst index a2dbcb7ea2d..478585a44e0 100644 --- a/service_container/calls.rst +++ b/service_container/calls.rst @@ -66,8 +66,13 @@ To configure the container to call the ``setLogger`` method, use the ``calls`` k .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Service\MessageGenerator; - use Symfony\Component\DependencyInjection\Reference; - $container->register(MessageGenerator::class) - ->addMethodCall('setLogger', [new Reference('logger')]); + return function(ContainerConfigurator $configurator) { + // ... + $container->set(MessageGenerator::class) + ->call('setLogger', [ref('logger')]); + }; + diff --git a/service_container/configurators.rst b/service_container/configurators.rst index 29b06bdea69..aa4fdf65c31 100644 --- a/service_container/configurators.rst +++ b/service_container/configurators.rst @@ -166,23 +166,22 @@ all the classes are already loaded as services. All you need to do is specify th .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + use App\Mail\EmailConfigurator; use App\Mail\GreetingCardManager; use App\Mail\NewsletterManager; - use Symfony\Component\DependencyInjection\Definition; - use Symfony\Component\DependencyInjection\Reference; - // Same as before - $definition = new Definition(); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); - $definition->setAutowired(true); + $container->load('App\', '../src/*'); + $container->set(NewsletterManager::class) + ->configurator(ref(EmailConfigurator::class), 'configure'); - $this->registerClasses($definition, 'App\\', '../src/*'); - - $container->getDefinition(NewsletterManager::class) - ->setConfigurator([new Reference(EmailConfigurator::class), 'configure']); - - $container->getDefinition(GreetingCardManager::class) - ->setConfigurator([new Reference(EmailConfigurator::class), 'configure']); + $container->set(GreetingCardManager::class) + ->configurator(ref(EmailConfigurator::class), 'configure'); + }; .. _configurators-invokable: diff --git a/service_container/expression_language.rst b/service_container/expression_language.rst index ce41f0e184c..d51d4ecbc02 100644 --- a/service_container/expression_language.rst +++ b/service_container/expression_language.rst @@ -53,14 +53,19 @@ to another service: ``App\Mailer``. One way to do this is with an expression: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Mail\MailerConfiguration; use App\Mailer; - use Symfony\Component\ExpressionLanguage\Expression; - $container->autowire(MailerConfiguration::class); + return function(ContainerConfigurator $configurator) { + // ... + $container->set(MailerConfiguration::class); + + $container->set(Mailer::class) + ->args([expr(sprintf('service(%s).getMailerMethod()', MailerConfiguration::class))]); + }; - $container->autowire(Mailer::class) - ->addArgument(new Expression('service("App\\\\Mail\\\\MailerConfiguration").getMailerMethod()')); To learn more about the expression language syntax, see :doc:`/components/expression_language/syntax`. @@ -102,13 +107,16 @@ via a ``container`` variable. Here's another example: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Mailer; - use Symfony\Component\ExpressionLanguage\Expression; - $container->autowire(Mailer::class) - ->addArgument(new Expression( - "container.hasParameter('some_param') ? parameter('some_param') : 'default_value'" - )); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(Mailer::class) + ->args([expr("container.hasParameter('some_param') ? parameter('some_param') : 'default_value'")]); + }; Expressions can be used in ``arguments``, ``properties``, as arguments with ``configurator`` and as arguments to ``calls`` (method calls). diff --git a/service_container/factories.rst b/service_container/factories.rst index 2c926bab59c..c847c4abb2b 100644 --- a/service_container/factories.rst +++ b/service_container/factories.rst @@ -69,13 +69,18 @@ configure the service container to use the .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Email\NewsletterManager; use App\Email\NewsletterManagerStaticFactory; - // ... - $container->register(NewsletterManager::class) - // call the static method - ->setFactory([NewsletterManagerStaticFactory::class, 'createNewsletterManager']); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(NewsletterManager::class) + ->factory([NewsletterManagerStaticFactory::class, 'createNewsletterManager']); + }; + .. note:: @@ -130,19 +135,17 @@ Configuration of the service container then looks like this: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Email\NewsletterManager; use App\Email\NewsletterManagerFactory; - use Symfony\Component\DependencyInjection\Reference; - // ... - $container->register(NewsletterManagerFactory::class); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); - $container->register(NewsletterManager::class) - // call a method on the specified factory service - ->setFactory([ - new Reference(NewsletterManagerFactory::class), - 'createNewsletterManager', - ]); + $container->set(NewsletterManager::class) + ->factory([ref(NewsletterManagerFactory::class), 'createNewsletterManager']); + }; .. _factories-invokable: @@ -259,14 +262,16 @@ example takes the ``templating`` service as an argument: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Email\NewsletterManager; use App\Email\NewsletterManagerFactory; - use Symfony\Component\DependencyInjection\Reference; - // ... - $container->register(NewsletterManager::class) - ->addArgument(new Reference('templating')) - ->setFactory([ - new Reference(NewsletterManagerFactory::class), - 'createNewsletterManager', - ]); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(NewsletterManager::class) + ->args([ref('templating')]) + ->factory([ref(NewsletterManagerFactory::class), 'createNewsletterManager']); + }; + diff --git a/service_container/import.rst b/service_container/import.rst index 8dc63c800b1..3c1f82f6f69 100644 --- a/service_container/import.rst +++ b/service_container/import.rst @@ -117,19 +117,21 @@ a relative or absolute path to the imported file: .. code-block:: php // config/services.php - use Symfony\Component\DependencyInjection\Definition; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - $loader->import('services/mailer.php'); + return function(ContainerConfigurator $configurator) { + $configurator->import('services/mailer.php'); - $definition = new Definition(); - $definition - ->setAutowired(true) - ->setAutoconfigured(true) - ->setPublic(false) - ; + $container = $configurator->services() + ->defaults() + ->autowire() + ->autoconfigure() + ->private() + ; - $this->registerClasses($definition, 'App\\', '../src/*', - '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'); + $container->load('App\\', '../src/*') + ->exclude('../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'); + }; When loading a configuration file, Symfony loads first the imported files and then it processes the parameters and services defined in the file. If you use the diff --git a/service_container/injection_types.rst b/service_container/injection_types.rst index 72faffd7a8b..2403d350b99 100644 --- a/service_container/injection_types.rst +++ b/service_container/injection_types.rst @@ -69,12 +69,16 @@ service container configuration: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Mail\NewsletterManager; - use Symfony\Component\DependencyInjection\Reference; - // ... - $container->register(NewsletterManager::class) - ->addArgument(new Reference('mailer')); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(NewsletterManager::class) + ->args(ref('mailer')); + }; + .. tip:: @@ -155,12 +159,15 @@ that accepts the dependency:: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Mail\NewsletterManager; - use Symfony\Component\DependencyInjection\Reference; - // ... - $container->register('app.newsletter_manager', NewsletterManager::class) - ->addMethodCall('setMailer', [new Reference('mailer')]); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(NewsletterManager::class) + ->call('setMailer', [ref('mailer')]); + }; This time the advantages are: @@ -228,12 +235,15 @@ Another possibility is setting public fields of the class directly:: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Mail\NewsletterManager; - use Symfony\Component\DependencyInjection\Reference; - // ... - $container->register('newsletter_manager', NewsletterManager::class) - ->setProperty('mailer', new Reference('mailer')); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set('app.newsletter_manager, NewsletterManager::class) + ->property('mailer', ref('mailer')); + }; There are mainly only disadvantages to using property injection, it is similar to setter injection but with these additional important problems: diff --git a/service_container/lazy_services.rst b/service_container/lazy_services.rst index fa198777e3e..54b85da121f 100644 --- a/service_container/lazy_services.rst +++ b/service_container/lazy_services.rst @@ -64,10 +64,15 @@ You can mark the service as ``lazy`` by manipulating its definition: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Twig\AppExtension; - $container->register(AppExtension::class) - ->setLazy(true); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(AppExtension::class)->lazy(); + }; + Once you inject the service into another service, a virtual `proxy`_ with the same signature of the class representing the service should be injected. The diff --git a/service_container/optional_dependencies.rst b/service_container/optional_dependencies.rst index fd3fa399ec8..89de31556a0 100644 --- a/service_container/optional_dependencies.rst +++ b/service_container/optional_dependencies.rst @@ -34,17 +34,16 @@ if the service does not exist: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Newsletter\NewsletterManager; - use Symfony\Component\DependencyInjection\ContainerInterface; - use Symfony\Component\DependencyInjection\Reference; - // ... + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(NewsletterManager::class) + ->args([ref('logger')->nullOnInvalid()]); + }; - $container->register(NewsletterManager::class) - ->addArgument(new Reference( - 'logger', - ContainerInterface::NULL_ON_INVALID_REFERENCE - )); .. note:: @@ -91,19 +90,16 @@ call if the service exists and remove the method call if it does not: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Newsletter\NewsletterManager; - use Symfony\Component\DependencyInjection\ContainerInterface; - use Symfony\Component\DependencyInjection\Reference; - - $container - ->register(NewsletterManager::class) - ->addMethodCall('setLogger', [ - new Reference( - 'logger', - ContainerInterface::IGNORE_ON_INVALID_REFERENCE - ), - ]) - ; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(NewsletterManager::class) + ->call('setLogger', [ref('logger')->ignoreOnInvalid()]) + ; + }; .. note:: diff --git a/service_container/parent_services.rst b/service_container/parent_services.rst index 9e6a3309444..806683c775b 100644 --- a/service_container/parent_services.rst +++ b/service_container/parent_services.rst @@ -117,28 +117,22 @@ duplicated service definitions: .. code-block:: php // config/services.php - use App\Repository\BaseDoctrineRepository; - use App\Repository\DoctrinePostRepository; - use App\Repository\DoctrineUserRepository; - use Symfony\Component\DependencyInjection\ChildDefinition; - use Symfony\Component\DependencyInjection\Reference; - - $container->register(BaseDoctrineRepository::class) - ->setAbstract(true) - ->addArgument(new Reference('doctrine.orm.entity_manager')) - ->addMethodCall('setLogger', [new Reference('logger')]) - ; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - // extend the App\Repository\BaseDoctrineRepository service - $definition = new ChildDefinition(BaseDoctrineRepository::class); - $definition->setClass(DoctrineUserRepository::class); - $container->setDefinition(DoctrineUserRepository::class, $definition); - - $definition = new ChildDefinition(BaseDoctrineRepository::class); - $definition->setClass(DoctrinePostRepository::class); - $container->setDefinition(DoctrinePostRepository::class, $definition); + use App\Repository\DoctrineUserRepository; + use App\Repository\DoctrinePostRepository; + use App\Repository\BaseDoctrineRepository; - // ... + return function(ContainerConfigurator $configurator) { + $configurator->services() + ->set(BaseDoctrineRepository::class) // NOTE: this must be set outside of a defaults section so that it can be extended + ->abstract() + ->args([ref('doctrine.orm.entity_manager')]) + ->call('setLogger', [ref('logger')]) + ->set(DoctrineUserRepository::class)->parent(BaseDoctrineRepository::class) + ->set(DoctrinePostRepository::class)->parent(BaseDoctrineRepository::class) + ; + }; In this context, having a ``parent`` service implies that the arguments and method calls of the parent service should be used for the child services. @@ -229,23 +223,23 @@ the child class: .. code-block:: php // config/services.php - use App\Repository\BaseDoctrineRepository; - use App\Repository\DoctrinePostRepository; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Repository\DoctrineUserRepository; - use Symfony\Component\DependencyInjection\ChildDefinition; - use Symfony\Component\DependencyInjection\Reference; + use App\Repository\DoctrinePostRepository; + use App\Repository\BaseDoctrineRepository; // ... - $definition = new ChildDefinition(BaseDoctrineRepository::class); - $definition->setClass(DoctrineUserRepository::class); - // overrides the public setting of the parent service - $definition->setPublic(false); - // appends the '@app.username_checker' argument to the parent argument list - $definition->addArgument(new Reference('app.username_checker')); - $container->setDefinition(DoctrineUserRepository::class, $definition); - - $definition = new ChildDefinition(BaseDoctrineRepository::class); - $definition->setClass(DoctrinePostRepository::class); - // overrides the first argument - $definition->replaceArgument(0, new Reference('doctrine.custom_entity_manager')); - $container->setDefinition(DoctrinePostRepository::class, $definition); + return function(ContainerConfigurator $configurator) { + $configurator->services() + ->set(BaseDoctrineRepository::class) // NOTE: this must be set outside of a defaults section so that it can be extended + // ... + ->set(DoctrineUserRepository::class) + ->parent(BaseDoctrineRepository::class) + ->private() + ->arg(1, ref('app.username_checker')) + ->set(DoctrinePostRepository::class) + ->parent(BaseDoctrineRepository::class) + ->arg(0, ref('doctrine.custom_entity_manager')) + ; + }; diff --git a/service_container/service_decoration.rst b/service_container/service_decoration.rst index 0904f9cb500..db90f63345f 100644 --- a/service_container/service_decoration.rst +++ b/service_container/service_decoration.rst @@ -39,14 +39,20 @@ When overriding an existing definition, the original service is lost: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Mailer; use App\NewMailer; - $container->register(Mailer::class); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(Mailer::class); - // this replaces the old App\Mailer definition with the new one, the - // old definition is lost - $container->register(Mailer::class, NewMailer::class); + // this replaces the old App\Mailer definition with the new one, the + // old definition is lost + $container->set(Mailer::class, NewMailer::class); + }; Most of the time, that's exactly what you want to do. But sometimes, you might want to decorate the old one instead (i.e. apply the `Decorator pattern`_). @@ -88,15 +94,18 @@ but keeps a reference of the old one as ``App\DecoratingMailer.inner``: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\DecoratingMailer; use App\Mailer; - use Symfony\Component\DependencyInjection\Reference; - $container->register(Mailer::class); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); - $container->register(DecoratingMailer::class) - ->setDecoratedService(Mailer::class) - ; + $container->set(Mailer::class); + $container->set(DecoratingMailer::class) + ->decorate(Mailer::class); + }; The ``decorates`` option tells the container that the ``App\DecoratingMailer`` service replaces the ``App\Mailer`` service. If you're using the @@ -145,16 +154,20 @@ automatically changed to ``decorating_service_id + '.inner'``): .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\DecoratingMailer; use App\Mailer; - use Symfony\Component\DependencyInjection\Reference; - $container->register(Mailer::class); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(Mailer::class); + $container->set(DecoratingMailer::class) + ->decorate(Mailer::class) + ->args([ref(DecoratingMailer::class.'.inner')]); + }; - $container->register(DecoratingMailer::class) - ->setDecoratedService(Mailer::class) - ->addArgument(new Reference(DecoratingMailer::class.'.inner')) - ; .. tip:: @@ -206,14 +219,19 @@ automatically changed to ``decorating_service_id + '.inner'``): .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\DecoratingMailer; - use Symfony\Component\DependencyInjection\Reference; + use App\Mailer; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); - $container->register(DecoratingMailer::class) - ->setDecoratedService(App\Mailer, DecoratingMailer::class.'.wooz') - ->addArgument(new Reference(DecoratingMailer::class.'.wooz')) - // ... - ; + $container->set(Mailer::class); + $container->set(DecoratingMailer::class) + ->decorate(Mailer::class, DecoratingMailer::class.'.wooz') + ->args([ref(DecoratingMailer::class.'.wooz')]); + }; Decoration Priority ------------------- @@ -266,19 +284,24 @@ the ``decoration_priority`` option. Its value is an integer that defaults to .. code-block:: php // config/services.php - use Symfony\Component\DependencyInjection\Reference; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(Foo::class); - $container->register(Foo::class) + $container->set(Bar::class) + ->decorate(Foo::class, null, 5) + ->private() + ->args([ref(Bar::class.'.inner')]); - $container->register(Bar::class) - ->addArgument(new Reference(Bar::class.'.inner')) - ->setPublic(false) - ->setDecoratedService(Foo::class, null, 5); + $container->set(Baz::class) + ->decorate(Foo::class, null, 1) + ->private() + ->args([ref(Baz::class.'.inner')]); + }; - $container->register(Baz::class) - ->addArgument(new Reference(Baz::class.'.inner')) - ->setPublic(false) - ->setDecoratedService(Foo::class, null, 1); The generated code will be the following:: diff --git a/service_container/service_subscribers_locators.rst b/service_container/service_subscribers_locators.rst index 952e61fee77..e1eb289f522 100644 --- a/service_container/service_subscribers_locators.rst +++ b/service_container/service_subscribers_locators.rst @@ -225,14 +225,16 @@ service type to a service. .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\CommandBus; - // ... + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); - $container - ->register(CommandBus::class) - ->addTag('container.service_subscriber', ['key' => 'logger', 'id' => 'monolog.logger.event']) - ; + $container->set(CommandBus::class) + ->tag('container.service_subscriber', ['key' => 'logger', 'id' => 'monolog.logger.event']); + }; .. tip:: @@ -299,23 +301,24 @@ service definition to pass a collection of services to the service locator: .. code-block:: php // config/services.php - use Symfony\Component\DependencyInjection\Reference; - use Symfony\Component\DependencyInjection\ServiceLocator; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - // ... + use Symfony\Component\DependencyInjection\ServiceLocator; - $container - ->register('app.command_handler_locator', ServiceLocator::class) - ->setArguments([[ - 'App\FooCommand' => new Reference('app.command_handler.foo'), - 'App\BarCommand' => new Reference('app.command_handler.bar'), - // if the element has no key, the ID of the original service is used - new Reference('app.command_handler.baz'), - ))) - // if you are not using the default service autoconfiguration, - // add the following tag to the service definition: - // ->addTag('container.service_locator') - ; + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set('app.command_handler_locator', ServiceLocator::class) + ->args([[ + 'App\FooCommand' => ref('app.command_handler.foo'), + 'App\BarCommand' => ref('app.command_handler.bar'), + ref('app.command_handler.baz'), + ]]) + // if you are not using the default service autoconfiguration, + // add the following tag to the service definition: + // ->tag('container.service_locator'); + ; + }; .. versionadded:: 4.1 @@ -364,13 +367,16 @@ Now you can use the service locator by injecting it in any other service: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\CommandBus; - use Symfony\Component\DependencyInjection\Reference; - $container - ->register(CommandBus::class) - ->setArguments([new Reference('app.command_handler_locator')]) - ; + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(CommandBus::class) + ->args([ref('app.command_handler_locator')]); + }; In :doc:`compiler passes ` it's recommended to use the :method:`Symfony\\Component\\DependencyInjection\\Compiler\\ServiceLocatorTagPass::register` @@ -448,18 +454,24 @@ of the ``key`` tag attribute (as defined in the ``index_by`` locator option): .. code-block:: php // config/services.php - use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; - use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); - $container->register(App\Handler\One::class) - ->addTag('app.handler', ['key' => 'handler_one']); + $container->set(App\Handler\One::class) + ->tag('app.handler', ['key' => 'handler_one']) + ; - $container->register(App\Handler\Two::class) - ->addTag('app.handler', ['key' => 'handler_two']); + $container->set(App\Handler\Two::class) + ->tag('app.handler', ['key' => 'handler_two']) + ; - $container->register(App\Handler\HandlerCollection::class) - // inject all services tagged with app.handler as first argument - ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', 'key'))); + $container->set(App\Handler\HandlerCollection::class) + // inject all services tagged with app.handler as first argument + ->args([tagged_locator('app.handler', 'key')]) + ; + }; Inside this locator you can retrieve services by index using the value of the ``key`` attribute. For example, to get the ``App\Handler\Two`` service:: @@ -532,10 +544,14 @@ attribute to the locator service defining the name of this custom method: .. code-block:: php // config/services.php - // ... - - $container->register(App\HandlerCollection::class) - ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('app.handler', null, 'myOwnMethodName'))); + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + $configurator->services() + ->set(App\HandlerCollection::class) + ->args([service_locator(tagged('app.handler', null, 'myOwnMethodName'))]) + ; + }; Service Subscriber Trait ------------------------ diff --git a/service_container/shared.rst b/service_container/shared.rst index 00f0ddf0e43..42e1c1e877d 100644 --- a/service_container/shared.rst +++ b/service_container/shared.rst @@ -32,10 +32,16 @@ in your service definition: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\SomeNonSharedService; - $container->register(SomeNonSharedService::class) - ->setShared(false); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + + $container->set(SomeNonSharedService::class) + ->share(false); + }; Now, whenever you request the ``App\SomeNonSharedService`` from the container, you will be passed a new instance. diff --git a/service_container/synthetic_services.rst b/service_container/synthetic_services.rst index ad4cc9924ff..30c626b59f5 100644 --- a/service_container/synthetic_services.rst +++ b/service_container/synthetic_services.rst @@ -64,10 +64,14 @@ configuration: .. code-block:: php // config/services.php - // synthetic services don't specify a class - $container->register('app.synthetic_service') - ->setSynthetic(true) - ; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set('app.synthetic_service') + ->synthetic(); + }; + Now, you can inject the instance in the container using :method:`Container::set() `:: diff --git a/service_container/tags.rst b/service_container/tags.rst index 9a98cf17619..187d50a52e9 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -38,11 +38,17 @@ example: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Twig\AppExtension; - $container->register(AppExtension::class) - ->setPublic(false) - ->addTag('twig.extension'); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(AppExtension::class) + ->private() + ->tag('twig.extension'); + }; + Services tagged with the ``twig.extension`` tag are collected during the initialization of TwigBundle and added to Twig as extensions. @@ -96,13 +102,17 @@ If you want to apply tags automatically for your own services, use the .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Security\CustomInterface; - // ... - // services whose classes are instances of CustomInterface will be tagged automatically - $container->registerForAutoconfiguration(CustomInterface::class) - ->addTag('app.custom_tag') - ->setAutowired(true); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->instanceof(CustomInterface::class) + ->autowire() + ->tag('app.custom_tag'); + }; + For more advanced needs, you can define the automatic tags using the :method:`Symfony\\Component\\DependencyInjection\\ContainerBuilder::registerForAutoconfiguration` @@ -182,9 +192,15 @@ Then, define the chain as a service: .. code-block:: php // config/services.php + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + use App\Mail\TransportChain; - $container->autowire(TransportChain::class); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(TransportChain::class); + }; + Define Services with a Custom Tag ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -231,12 +247,17 @@ For example, you may add the following transports as services: .. code-block:: php // config/services.php - $container->register(\Swift_SmtpTransport::class) - ->addArgument('%mailer_host%') - ->addTag('app.mail_transport'); + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(\Swift_SmtpTransport::class) + ->args(['%mailer_host%']) + ->tag('app.mail_transport'); - $container->register(\Swift_SendmailTransport::class) - ->addTag('app.mail_transport'); + $container->set(\Swift_SendmailTransport::class) + ->tag('app.mail_transport'); + }; Notice that each service was given a tag named ``app.mail_transport``. This is the custom tag that you'll use in your compiler pass. The compiler pass is what @@ -387,12 +408,17 @@ To answer this, change the service declaration: .. code-block:: php // config/services.php - $container->register(\Swift_SmtpTransport::class) - ->addArgument('%mailer_host%') - ->addTag('app.mail_transport', ['alias' => 'smtp']); + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - $container->register(\Swift_SendmailTransport::class) - ->addTag('app.mail_transport', ['alias' => 'sendmail']); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(\Swift_SmtpTransport::class) + ->args(['%mailer_host%']) + ->tag('app.mail_transport', ['alias' => 'smtp']); + + $container->set(\Swift_SendmailTransport::class) + ->tag('app.mail_transport', ['alias' => 'sendmail']); + }; .. tip:: @@ -500,17 +526,20 @@ first constructor argument to the ``App\HandlerCollection`` service: .. code-block:: php // config/services.php - use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; + namespace Symfony\Component\DependencyInjection\Loader\Configurator; - $container->register(App\Handler\One::class) - ->addTag('app.handler'); + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(App\Handler\One::class) + ->tag('app.handler'); - $container->register(App\Handler\Two::class) - ->addTag('app.handler'); + $container->set(App\Handler\Two::class) + ->tag('app.handler'); - $container->register(App\HandlerCollection::class) - // inject all services tagged with app.handler as first argument - ->addArgument(new TaggedIteratorArgument('app.handler')); + $container->set(App\HandlerCollection::class) + // inject all services tagged with app.handler as first argument + ->args([tagged('app.handler')]); + }; After compilation the ``HandlerCollection`` service is able to iterate over your application handlers:: @@ -558,7 +587,12 @@ application handlers:: .. code-block:: php // config/services.php - $container->register(App\Handler\One::class) - ->addTag('app.handler', ['priority' => 20]); + namespace Symfony\Component\DependencyInjection\Loader\Configurator; + + return function(ContainerConfigurator $configurator) { + $container = $configurator->services(); + $container->set(App\Handler\One::class) + ->tag('app.handler', ['priority' => 20]); + }; Note that any other custom attributes will be ignored by this feature.