Symfony 7.3 introduces several enhancements to the DependencyInjection component that simplify service configuration, make autoconfiguration more flexible, and enable environment-specific aliasing.
Service Closure Shorthand
Service closures wrap the injected service into a closure allowing it to be lazily loaded only when needed. This is useful when the injected service is expensive to instantiate or only used in specific cases.
When using YAML config, you had to use the custom !service_closure
tag to
inject service closures. In Symfony 7.3, we've added a shortcut to configure
these service closures:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# config/services.yaml
services:
# this is the traditional way of defining service closures
App\Service\MyService:
arguments: [!service_closure '@mailer']
# in case the dependency is optional
# arguments: [!service_closure '@?mailer']
# '@>' is the new shortcut to define service closures
App\Service\AnotherService:
arguments: ['@>mailer']
# the shortcut also works for optional dependencies
# arguments: ['@>?mailer']
Defining Aliases per Environment
Service aliasing lets you create an alternative ID for existing services. They're useful for defining shortcuts, renaming services without removing the original ones, and more.
In Symfony 7.3, we're improving service aliases so you can define aliases only on certain environments. This is useful for example to create aliases only in the test configuration environment for testing purposes:
1 2 3 4 5 6 7 8 9 10 11
// src/Some/Service.php
namespace App\Some;
// ...
use Symfony\Component\DependencyInjection\Attribute\AsAlias;
#[AsAlias(id: 'app.foo', when: 'test')]
class Service
{
// ...
}
You can pass more than one environment name if needed:
1
#[AsAlias(id: 'app.foo', when: ['dev', 'test'])]
Resource Tags
Sometimes you want to exclude certain classes like model classes, entities,
etc. from service autoconfiguration. However, this prevents tagging those
classes with a service tag and later using methods like findTaggedServiceIds()
to find them.
In Symfony 7.3, we've improved the service container so you can find tagged
classes even if they are not registered as services. For example, suppose
your application defines a PHP attribute called #[AppModel]
, which you
apply to all model classes that should not be registered as services.
Then, in a service container extension, you can use autoconfiguration to
find all classes with that PHP attribute and apply a tag to them using
the new addResourceTag()
method:
1 2 3 4 5 6 7 8
$this->registerAttributeForAutoconfiguration(AppModel::class, static function (ChildDefinition $definition) {
// this is the new method introduced in Symfony 7.3
$definition->addResourceTag('app.model');
// there's no need to apply the following tag because it's automatically
// applied by Symfony for you to not register these classes as services
// $definition->addTag('container.excluded');
});
Related to this change, Symfony 7.3 also improves the
registerAttributeForAutoconfiguration()
method, allowing you to call it
multiple times for the same PHP attribute. Previously, it could only be called
once per attribute.
Later, in a compiler pass, you can find these classes using the new
findTaggedResourceIds()
method:
1 2 3 4 5 6 7
$classes = [];
foreach($containerBuilder->findTaggedResourceIds('app.model') as $id => $tags) {
$classes[] = $containerBuilder->getDefinition($id)->getClass();
}
// save the list of classes as a container parameter to retrieve it later
$containerBuilder->setParameter('.app.model_classes', $classes);
Symfony itself now uses resource tags. If you check the service configuration
of your Symfony applications, you'll probably find the following exclude
lines:
1 2 3 4 5 6 7 8 9 10
# config/services.yaml
services:
# ...
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
Starting in Symfony 7.3, these default exclude lines are no longer necessary. Thanks to the new resource tags introduced in this version, service container extensions, test cases, Doctrine entities, and Messenger messages are now automatically tagged and excluded for you.
Special thanks to Jérôme for helping review the contents of this post.