Built-in Symfony Service Tags ============================= :doc:`Service tags ` are the mechanism used by the :doc:`DependencyInjection component ` to flag services that require special processing, like console commands or Twig extensions. These are the most common tags provided by Symfony components, but in your application there could be more tags available provided by third-party bundles: ======================================== ======================================================================== Tag Name Usage ======================================== ======================================================================== `auto_alias`_ Define aliases based on the value of container parameters `console.command`_ Add a command `container.hot_path`_ Add to list of always needed services `container.no_preload`_ Remove a class from the list of classes preloaded by PHP `container.preload`_ Add some class to the list of classes preloaded by PHP `controller.argument_value_resolver`_ Register a value resolver for controller arguments such as ``Request`` `data_collector`_ Create a class that collects custom data for the profiler `doctrine.event_listener`_ Add a Doctrine event listener `doctrine.event_subscriber`_ Add a Doctrine event subscriber `form.type`_ Create a custom form field type `form.type_extension`_ Create a custom "form extension" `form.type_guesser`_ Add your own logic for "form type guessing" `kernel.cache_clearer`_ Register your service to be called during the cache clearing process `kernel.cache_warmer`_ Register your service to be called during the cache warming process `kernel.event_listener`_ Listen to different events/hooks in Symfony `kernel.event_subscriber`_ To subscribe to a set of different events/hooks in Symfony `kernel.fragment_renderer`_ Add new HTTP content rendering strategies `kernel.reset`_ Allows to clean up services between requests `mime.mime_type_guesser`_ Add your own logic for guessing MIME types `monolog.logger`_ Logging with a custom logging channel `monolog.processor`_ Add a custom processor for logging `routing.loader`_ Register a custom service that loads routes `routing.expression_language_provider`_ Register a provider for expression language functions in routing `security.expression_language_provider`_ Register a provider for expression language functions in security `security.voter`_ Add a custom voter to Symfony's authorization logic `security.remember_me_aware`_ To allow remember me authentication `serializer.encoder`_ Register a new encoder in the ``serializer`` service `serializer.normalizer`_ Register a new normalizer in the ``serializer`` service `swiftmailer.default.plugin`_ Register a custom SwiftMailer Plugin `translation.loader`_ Register a custom service that loads translations `translation.extractor`_ Register a custom service that extracts translation messages from a file `translation.dumper`_ Register a custom service that dumps translation messages `twig.extension`_ Register a custom Twig Extension `twig.loader`_ Register a custom service that loads Twig templates `twig.runtime`_ Register a lazy-loaded Twig Extension `validator.constraint_validator`_ Create your own custom validation constraint `validator.initializer`_ Register a service that initializes objects before validation ======================================== ======================================================================== auto_alias ---------- **Purpose**: Define aliases based on the value of container parameters Consider the following configuration that defines three different but related services: .. configuration-block:: .. code-block:: yaml services: app.mysql_lock: class: App\Lock\MysqlLock app.postgresql_lock: class: App\Lock\PostgresqlLock app.sqlite_lock: class: App\Lock\SqliteLock .. code-block:: xml .. code-block:: php // config/services.php namespace Symfony\Component\DependencyInjection\Loader\Configurator; use App\Lock\MysqlLock; use App\Lock\PostgresqlLock; use App\Lock\SqliteLock; return function(ContainerConfigurator $configurator) { $services = $configurator->services(); $services->set('app.mysql_lock', MysqlLock::class); $services->set('app.postgresql_lock', PostgresqlLock::class); $services->set('app.sqlite_lock', SqliteLock::class); }; Instead of dealing with these three services, your application needs a generic ``app.lock`` service that will be an alias to one of these services, depending on some configuration. Thanks to the ``auto_alias`` option, you can automatically create that alias based on the value of a configuration parameter. Considering that a configuration parameter called ``database_type`` exists. Then, the generic ``app.lock`` service can be defined as follows: .. configuration-block:: .. code-block:: yaml services: app.mysql_lock: # ... app.postgresql_lock: # ... app.sqlite_lock: # ... app.lock: tags: - { name: auto_alias, format: "app.%database_type%_lock" } .. code-block:: xml .. code-block:: php // config/services.php namespace Symfony\Component\DependencyInjection\Loader\Configurator; use App\Lock\MysqlLock; use App\Lock\PostgresqlLock; use App\Lock\SqliteLock; return function(ContainerConfigurator $configurator) { $services = $configurator->services(); $services->set('app.mysql_lock', MysqlLock::class); $services->set('app.postgresql_lock', PostgresqlLock::class); $services->set('app.sqlite_lock', SqliteLock::class); $services->set('app.lock') ->tag('auto_alias', ['format' => 'app.%database_type%_lock']) ; }; The ``format`` option defines the expression used to construct the name of the service to alias. This expression can use any container parameter (as usual, wrapping their names with ``%`` characters). .. note:: When using the ``auto_alias`` tag, it's not mandatory to define the aliased services as private. However, doing that (like in the above example) makes sense most of the times to prevent accessing those services directly instead of using the generic service alias. .. versionadded:: 5.1 In Symfony versions prior to 5.1, you needed to manually add the ``Symfony\Component\DependencyInjection\Compiler\AutoAliasServicePass`` compiler pass to the container for this feature to work. This compiler pass is now added automatically. console.command --------------- **Purpose**: Add a command to the application For details on registering your own commands in the service container, read :doc:`/console/commands_as_services`. container.hot_path ------------------ **Purpose**: Add to list of always needed services This tag identifies the services that are always needed. It is only applied to a very short list of bootstrapping services (like ``router``, ``event_dispatcher``, ``http_kernel``, ``request_stack``, etc.). Then, it is propagated to all dependencies of these services, with a special case for event listeners, where only listed events are propagated to their related listeners. It will replace, in cache for generated service factories, the PHP autoload by plain inlined ``include_once``. The benefit is a complete bypass of the autoloader for services and their class hierarchy. The result is as significant performance improvement. Use this tag with great caution, you have to be sure that the tagged service is always used. .. _dic-tags-container-nopreload: container.no_preload -------------------- **Purpose**: Remove a class from the list of classes preloaded by PHP .. versionadded:: 5.1 The ``container.no_preload`` tag was introduced in Symfony 5.1. Add this tag to a service and its class won't be preloaded when using `PHP class preloading`_: .. configuration-block:: .. code-block:: yaml services: App\SomeNamespace\SomeService: tags: ['container.no_preload'] .. code-block:: xml .. code-block:: php use App\SomeNamespace\SomeService; $container ->register(SomeService::class) ->addTag('container.no_preload') ; .. _dic-tags-container-preload: container.preload ----------------- **Purpose**: Add some class to the list of classes preloaded by PHP .. versionadded:: 5.1 The ``container.preload`` tag was introduced in Symfony 5.1. When using `PHP class preloading`_, this tag allows you to define which PHP classes should be preloaded. This can improve performance by making some of the classes used by your service always available for all requests (until the server is restarted): .. configuration-block:: .. code-block:: yaml services: App\SomeNamespace\SomeService: tags: - { name: 'container.preload', class: 'App\SomeClass' } - { name: 'container.preload', class: 'App\Some\OtherClass' } # ... .. code-block:: xml .. code-block:: php use App\Some\OtherClass; use App\SomeClass; use App\SomeNamespace\SomeService; $container ->register(SomeService::class) ->addTag('container.preload', ['class' => SomeClass::class) ->addTag('container.preload', ['class' => OtherClass::class) // ... ; controller.argument_value_resolver ---------------------------------- **Purpose**: Register a value resolver for controller arguments such as ``Request`` Value resolvers implement the :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentValueResolverInterface` and are used to resolve argument values for controllers as described here: :doc:`/controller/argument_value_resolver`. data_collector -------------- **Purpose**: Create a class that collects custom data for the profiler For details on creating your own custom data collection, read the :doc:`/profiler/data_collector` article. doctrine.event_listener ----------------------- **Purpose**: Add a Doctrine event listener For details on creating Doctrine event listeners, read the :doc:`Doctrine events ` article. doctrine.event_subscriber ------------------------- **Purpose**: Add a Doctrine event subscriber For details on creating Doctrine event subscribers, read the :doc:`Doctrine events ` article. .. _dic-tags-form-type: form.type --------- **Purpose**: Create a custom form field type For details on creating your own custom form type, read the :doc:`/form/create_custom_field_type` article. form.type_extension ------------------- **Purpose**: Create a custom "form extension" For details on creating Form type extensions, read the :doc:`/form/create_form_type_extension` article. .. _reference-dic-type_guesser: form.type_guesser ----------------- **Purpose**: Add your own logic for "form type guessing" This tag allows you to add your own logic to the :ref:`form guessing ` process. By default, form guessing is done by "guessers" based on the validation metadata and Doctrine metadata (if you're using Doctrine) or Propel metadata (if you're using Propel). .. seealso:: For information on how to create your own type guesser, see :doc:`/form/type_guesser`. kernel.cache_clearer -------------------- **Purpose**: Register your service to be called during the cache clearing process Cache clearing occurs whenever you call ``cache:clear`` command. If your bundle caches files, you should add custom cache clearer for clearing those files during the cache clearing process. In order to register your custom cache clearer, first you must create a service class:: // src/Cache/MyClearer.php namespace App\Cache; use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface; class MyClearer implements CacheClearerInterface { public function clear($cacheDirectory) { // clear your cache } } If you're using the :ref:`default services.yaml configuration `, your service will be automatically tagged with ``kernel.cache_clearer``. But, you can also register it manually: .. configuration-block:: .. code-block:: yaml services: App\Cache\MyClearer: tags: [kernel.cache_clearer] .. code-block:: xml .. code-block:: php use App\Cache\MyClearer; $container ->register(MyClearer::class) ->addTag('kernel.cache_clearer') ; kernel.cache_warmer ------------------- **Purpose**: Register your service to be called during the cache warming process Cache warming occurs whenever you run the ``cache:warmup`` or ``cache:clear`` command (unless you pass ``--no-warmup`` to ``cache:clear``). It is also run when handling the request, if it wasn't done by one of the commands yet. The purpose is to initialize any cache that will be needed by the application and prevent the first user from any significant "cache hit" where the cache is generated dynamically. To register your own cache warmer, first create a service that implements the :class:`Symfony\\Component\\HttpKernel\\CacheWarmer\\CacheWarmerInterface` interface:: // src/Cache/MyCustomWarmer.php namespace App\Cache; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; class MyCustomWarmer implements CacheWarmerInterface { public function warmUp($cacheDirectory) { // ... do some sort of operations to "warm" your cache } public function isOptional() { return true; } } The ``isOptional()`` method should return true if it's possible to use the application without calling this cache warmer. In Symfony, optional warmers are always executed by default (you can change this by using the ``--no-optional-warmers`` option when executing the command). If you're using the :ref:`default services.yaml configuration `, your service will be automatically tagged with ``kernel.cache_warmer``. But, you can also register it manually: .. configuration-block:: .. code-block:: yaml services: App\Cache\MyCustomWarmer: tags: - { name: kernel.cache_warmer, priority: 0 } .. code-block:: xml .. code-block:: php use App\Cache\MyCustomWarmer; $container ->register(MyCustomWarmer::class) ->addTag('kernel.cache_warmer', ['priority' => 0]) ; .. note:: The ``priority`` is optional and its value is a positive or negative integer that defaults to ``0``. The higher the number, the earlier that warmers are executed. .. caution:: If your cache warmer fails its execution because of any exception, Symfony won't try to execute it again for the next requests. Therefore, your application and/or bundles should be prepared for when the contents generated by the cache warmer are not available. .. _core-cache-warmers: In addition to your own cache warmers, Symfony components and third-party bundles define cache warmers too for their own purposes. You can list them all with the following command: .. code-block:: terminal $ php bin/console debug:container --tag=kernel.cache_warmer .. _dic-tags-kernel-event-listener: kernel.event_listener --------------------- **Purpose**: To listen to different events/hooks in Symfony During the execution of a Symfony application, different events are triggered and you can also dispatch custom events. This tag allows you to *hook* your own classes into any of those events. For a full example of this listener, read the :doc:`/event_dispatcher` article. Core Event Listener Reference ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For the reference of Event Listeners associated with each kernel event, see the :doc:`Symfony Events Reference `. .. _dic-tags-kernel-event-subscriber: kernel.event_subscriber ----------------------- **Purpose**: To subscribe to a set of different events/hooks in Symfony This is an alternative way to create an event listener, and is the recommended way (instead of using ``kernel.event_listener``). See :ref:`events-subscriber`. kernel.fragment_renderer ------------------------ **Purpose**: Add a new HTTP content rendering strategy To add a new rendering strategy - in addition to the core strategies like ``EsiFragmentRenderer`` - create a class that implements :class:`Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface`, register it as a service, then tag it with ``kernel.fragment_renderer``. kernel.reset ------------ **Purpose**: Clean up services between requests During the ``kernel.terminate`` event, Symfony looks for any service tagged with the ``kernel.reset`` tag to reinitialize their state. This is done by calling to the method whose name is configured in the ``method`` argument of the tag. This is mostly useful when running your projects in application servers that reuse the Symfony application between requests to improve performance. This tag is applied for example to the built-in :doc:`data collectors ` of the profiler to delete all their information. .. _dic_tags-mime: mime.mime_type_guesser ---------------------- **Purpose**: Add your own logic for guessing MIME types This tag is used to register your own :ref:`MIME type guessers ` in case the guessers provided by the :doc:`Mime component ` don't fit your needs. .. _dic_tags-monolog: monolog.logger -------------- **Purpose**: To use a custom logging channel with Monolog Monolog allows you to share its handlers between several logging channels. The logger service uses the channel ``app`` but you can change the channel when injecting the logger in a service. .. configuration-block:: .. code-block:: yaml services: App\Log\CustomLogger: arguments: ['@logger'] tags: - { name: monolog.logger, channel: app } .. code-block:: xml .. code-block:: php use App\Log\CustomLogger; use Symfony\Component\DependencyInjection\Reference; $container->register(CustomLogger::class) ->addArgument(new Reference('logger')) ->addTag('monolog.logger', ['channel' => 'app']); .. tip:: You can create :doc:`custom channels ` and even :ref:`autowire logging channels `. .. _dic_tags-monolog-processor: monolog.processor ----------------- **Purpose**: Add a custom processor for logging Monolog allows you to add processors in the logger or in the handlers to add extra data in the records. A processor receives the record as an argument and must return it after adding some extra data in the ``extra`` attribute of the record. The built-in ``IntrospectionProcessor`` can be used to add the file, the line, the class and the method where the logger was triggered. You can add a processor globally: .. configuration-block:: .. code-block:: yaml services: Monolog\Processor\IntrospectionProcessor: tags: [monolog.processor] .. code-block:: xml .. code-block:: php use Monolog\Processor\IntrospectionProcessor; $container ->register(IntrospectionProcessor::class) ->addTag('monolog.processor') ; .. tip:: If your service is not a callable (using ``__invoke()``) you can add the ``method`` attribute in the tag to use a specific method. You can add also a processor for a specific handler by using the ``handler`` attribute: .. configuration-block:: .. code-block:: yaml services: Monolog\Processor\IntrospectionProcessor: tags: - { name: monolog.processor, handler: firephp } .. code-block:: xml .. code-block:: php use Monolog\Processor\IntrospectionProcessor; $container ->register(IntrospectionProcessor::class) ->addTag('monolog.processor', ['handler' => 'firephp']) ; You can also add a processor for a specific logging channel by using the ``channel`` attribute. This will register the processor only for the ``security`` logging channel used in the Security component: .. configuration-block:: .. code-block:: yaml services: Monolog\Processor\IntrospectionProcessor: tags: - { name: monolog.processor, channel: security } .. code-block:: xml .. code-block:: php use Monolog\Processor\IntrospectionProcessor; $container ->register(IntrospectionProcessor::class) ->addTag('monolog.processor', ['channel' => 'security']) ; .. note:: You cannot use both the ``handler`` and ``channel`` attributes for the same tag as handlers are shared between all channels. routing.loader -------------- **Purpose**: Register a custom service that loads routes To enable a custom routing loader, add it as a regular service in one of your configuration and tag it with ``routing.loader``: .. configuration-block:: .. code-block:: yaml services: App\Routing\CustomLoader: tags: [routing.loader] .. code-block:: xml .. code-block:: php use App\Routing\CustomLoader; $container ->register(CustomLoader::class) ->addTag('routing.loader') ; For more information, see :doc:`/routing/custom_route_loader`. routing.expression_language_provider ------------------------------------ **Purpose**: Register a provider for expression language functions in routing This tag is used to automatically register :ref:`expression function providers ` for the routing expression component. Using these providers, you can add custom functions to the routing expression language. security.expression_language_provider ------------------------------------- **Purpose**: Register a provider for expression language functions in security This tag is used to automatically register :ref:`expression function providers ` for the security expression component. Using these providers, you can add custom functions to the security expression language. security.remember_me_aware -------------------------- **Purpose**: To allow remember me authentication This tag is used internally to allow remember-me authentication to work. If you have a custom authentication method where a user can be remember-me authenticated, then you may need to use this tag. If your custom authentication factory extends :class:`Symfony\\Bundle\\SecurityBundle\\DependencyInjection\\Security\\Factory\\AbstractFactory` and your custom authentication listener extends :class:`Symfony\\Component\\Security\\Http\\Firewall\\AbstractAuthenticationListener`, then your custom authentication listener will automatically have this tag applied and it will function automatically. security.voter -------------- **Purpose**: To add a custom voter to Symfony's authorization logic When you call ``isGranted()`` on Symfony's authorization checker, a system of "voters" is used behind the scenes to determine if the user should have access. The ``security.voter`` tag allows you to add your own custom voter to that system. For more information, read the :doc:`/security/voters` article. .. _reference-dic-tags-serializer-encoder: serializer.encoder ------------------ **Purpose**: Register a new encoder in the ``serializer`` service The class that's tagged should implement the :class:`Symfony\\Component\\Serializer\\Encoder\\EncoderInterface` and :class:`Symfony\\Component\\Serializer\\Encoder\\DecoderInterface`. For more details, see :doc:`/serializer`. .. _reference-dic-tags-serializer-normalizer: serializer.normalizer --------------------- **Purpose**: Register a new normalizer in the Serializer service The class that's tagged should implement the :class:`Symfony\\Component\\Serializer\\Normalizer\\NormalizerInterface` and :class:`Symfony\\Component\\Serializer\\Normalizer\\DenormalizerInterface`. For more details, see :doc:`/serializer`. The priorities of the default normalizers can be found in the :method:`Symfony\\Bundle\\FrameworkBundle\\DependencyInjection\\FrameworkExtension::registerSerializerConfiguration` method. swiftmailer.default.plugin -------------------------- **Purpose**: Register a custom SwiftMailer Plugin If you're using a custom SwiftMailer plugin (or want to create one), you can register it with SwiftMailer by creating a service for your plugin and tagging it with ``swiftmailer.default.plugin`` (it has no options). .. note:: ``default`` in this tag is the name of the mailer. If you have multiple mailers configured or have changed the default mailer name for some reason, you should change it to the name of your mailer in order to use this tag. A SwiftMailer plugin must implement the ``Swift_Events_EventListener`` interface. For more information on plugins, see `SwiftMailer's Plugin Documentation`_. Several SwiftMailer plugins are core to Symfony and can be activated via different configuration. For details, see :doc:`/reference/configuration/swiftmailer`. .. _dic-tags-translation-loader: translation.loader ------------------ **Purpose**: To register a custom service that loads translations By default, translations are loaded from the filesystem in a variety of different formats (YAML, XLIFF, PHP, etc). Now, register your loader as a service and tag it with ``translation.loader``: .. configuration-block:: .. code-block:: yaml services: App\Translation\MyCustomLoader: tags: - { name: translation.loader, alias: bin } .. code-block:: xml .. code-block:: php use App\Translation\MyCustomLoader; $container ->register(MyCustomLoader::class) ->addTag('translation.loader', ['alias' => 'bin']) ; The ``alias`` option is required and very important: it defines the file "suffix" that will be used for the resource files that use this loader. For example, suppose you have some custom ``bin`` format that you need to load. If you have a ``bin`` file that contains French translations for the ``messages`` domain, then you might have a file ``translations/messages.fr.bin``. When Symfony tries to load the ``bin`` file, it passes the path to your custom loader as the ``$resource`` argument. You can then perform any logic you need on that file in order to load your translations. If you're loading translations from a database, you'll still need a resource file, but it might either be blank or contain a little bit of information about loading those resources from the database. The file is key to trigger the ``load()`` method on your custom loader. .. _reference-dic-tags-translation-extractor: translation.extractor --------------------- **Purpose**: To register a custom service that extracts messages from a file When executing the ``translation:update`` command, it uses extractors to extract translation messages from a file. By default, the Symfony Framework has a :class:`Symfony\\Bridge\\Twig\\Translation\\TwigExtractor` and a :class:`Symfony\\Component\\Translation\\Extractor\\PhpExtractor`, which help to find and extract translation keys from Twig templates and PHP files. You can create your own extractor by creating a class that implements :class:`Symfony\\Component\\Translation\\Extractor\\ExtractorInterface` and tagging the service with ``translation.extractor``. The tag has one required option: ``alias``, which defines the name of the extractor:: // src/Acme/DemoBundle/Translation/FooExtractor.php namespace Acme\DemoBundle\Translation; use Symfony\Component\Translation\Extractor\ExtractorInterface; use Symfony\Component\Translation\MessageCatalogue; class FooExtractor implements ExtractorInterface { protected $prefix; /** * Extracts translation messages from a template directory to the catalog. */ public function extract($directory, MessageCatalogue $catalog) { // ... } /** * Sets the prefix that should be used for new found messages. */ public function setPrefix($prefix) { $this->prefix = $prefix; } } .. configuration-block:: .. code-block:: yaml services: App\Translation\CustomExtractor: tags: - { name: translation.extractor, alias: foo } .. code-block:: xml .. code-block:: php use App\Translation\CustomExtractor; $container->register(CustomExtractor::class) ->addTag('translation.extractor', ['alias' => 'foo']); translation.dumper ------------------ **Purpose**: To register a custom service that dumps messages to a file After a :ref:`translation extractor ` has extracted all messages from the templates, the dumpers are executed to dump the messages to a translation file in a specific format. Symfony already comes with many dumpers: * :class:`Symfony\\Component\\Translation\\Dumper\\CsvFileDumper` * :class:`Symfony\\Component\\Translation\\Dumper\\IcuResFileDumper` * :class:`Symfony\\Component\\Translation\\Dumper\\IniFileDumper` * :class:`Symfony\\Component\\Translation\\Dumper\\MoFileDumper` * :class:`Symfony\\Component\\Translation\\Dumper\\PoFileDumper` * :class:`Symfony\\Component\\Translation\\Dumper\\QtFileDumper` * :class:`Symfony\\Component\\Translation\\Dumper\\XliffFileDumper` * :class:`Symfony\\Component\\Translation\\Dumper\\YamlFileDumper` You can create your own dumper by extending :class:`Symfony\\Component\\Translation\\Dumper\\FileDumper` or implementing :class:`Symfony\\Component\\Translation\\Dumper\\DumperInterface` and tagging the service with ``translation.dumper``. The tag has one option: ``alias`` This is the name that's used to determine which dumper should be used. .. configuration-block:: .. code-block:: yaml services: App\Translation\JsonFileDumper: tags: - { name: translation.dumper, alias: json } .. code-block:: xml .. code-block:: php use App\Translation\JsonFileDumper; $container->register(JsonFileDumper::class) ->addTag('translation.dumper', ['alias' => 'json']); .. _reference-dic-tags-twig-extension: twig.extension -------------- **Purpose**: To register a custom Twig Extension To enable a Twig extension, add it as a regular service in one of your configuration and tag it with ``twig.extension``. If you're using the :ref:`default services.yaml configuration `, the service is auto-registered and auto-tagged. But, you can also register it manually: .. configuration-block:: .. code-block:: yaml services: App\Twig\AppExtension: tags: [twig.extension] # optionally you can define the priority of the extension (default = 0). # Extensions with higher priorities are registered earlier. This is mostly # useful to register late extensions that override other extensions. App\Twig\AnotherExtension: tags: [{ name: twig.extension, priority: -100 }] .. code-block:: xml .. code-block:: php use App\Twig\AnotherExtension; use App\Twig\AppExtension; $container ->register(AppExtension::class) ->addTag('twig.extension') ; $container ->register(AnotherExtension::class) ->addTag('twig.extension', ['priority' => -100]) ; For information on how to create the actual Twig Extension class, see `Twig's documentation`_ on the topic or read the :doc:`/templating/twig_extension` article. twig.loader ----------- **Purpose**: Register a custom service that loads Twig templates By default, Symfony uses only one `Twig Loader`_ - :class:`Symfony\\Bundle\\TwigBundle\\Loader\\FilesystemLoader`. If you need to load Twig templates from another resource, you can create a service for the new loader and tag it with ``twig.loader``. If you use the :ref:`default services.yaml configuration `, the service will be automatically tagged thanks to autoconfiguration. But, you can also register it manually: .. configuration-block:: .. code-block:: yaml services: App\Twig\CustomLoader: tags: - { name: twig.loader, priority: 0 } .. code-block:: xml .. code-block:: php use App\Twig\CustomLoader; $container ->register(CustomLoader::class) ->addTag('twig.loader', ['priority' => 0]) ; .. note:: The ``priority`` is optional and its value is a positive or negative integer that defaults to ``0``. Loaders with higher numbers are tried first. .. _reference-dic-tags-twig-runtime: twig.runtime ------------ **Purpose**: To register a custom Lazy-Loaded Twig Extension :ref:`Lazy-Loaded Twig Extensions ` are defined as regular services but the need to be tagged with ``twig.runtime``. If you're using the :ref:`default services.yaml configuration `, the service is auto-registered and auto-tagged. But, you can also register it manually: .. configuration-block:: .. code-block:: yaml services: App\Twig\AppExtension: tags: [twig.runtime] .. code-block:: xml .. code-block:: php use App\Twig\AppExtension; $container ->register(AppExtension::class) ->addTag('twig.runtime') ; validator.constraint_validator ------------------------------ **Purpose**: Create your own custom validation constraint This tag allows you to create and register your own custom validation constraint. For more information, read the :doc:`/validation/custom_constraint` article. validator.initializer --------------------- **Purpose**: Register a service that initializes objects before validation This tag provides a very uncommon piece of functionality that allows you to perform some sort of action on an object right before it's validated. For example, it's used by Doctrine to query for all of the lazily-loaded data on an object before it's validated. Without this, some data on a Doctrine entity would appear to be "missing" when validated, even though this is not really the case. If you do need to use this tag, just make a new class that implements the :class:`Symfony\\Component\\Validator\\ObjectInitializerInterface` interface. Then, tag it with the ``validator.initializer`` tag (it has no options). For an example, see the ``DoctrineInitializer`` class inside the Doctrine Bridge. .. _`Twig's documentation`: https://twig.symfony.com/doc/2.x/advanced.html#creating-an-extension .. _`SwiftMailer's Plugin Documentation`: https://swiftmailer.symfony.com/docs/plugins.html .. _`Twig Loader`: https://twig.symfony.com/doc/2.x/api.html#loaders .. _`PHP class preloading`: https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.preload