In Drupal, "tagged services" allow you to categorize and manage service definitions by assigning them specific tags. These tags help the service container understand the purpose of certain services, often to group them for a specific function. Tagged services are typically used with "collector services," which gather services with the same tag and utilize them for a specific purpose.
How Tagged Services Work:
1. Defining a Service with a Tag:
When defining a service in a *.services.yml file, you can apply a tag like this:
yaml
services:
my_module.some_service:
class: Drupal\my_module\SomeService
tags:
- { name: my_tag_name } In this example, my_module.some_service is tagged with my_tag_name. This tag can then be used to collect and process services related to this tag.
2. Using a Collector Service:
A collector service will usually look for all services with a specific tag and group them together. You can inject a tagged service into the collector service:
yaml
services:
my_module.collector_service:
class: Drupal\my_module\CollectorService
arguments: ['@service_container']Inside the collector service class, you can fetch tagged services like this:
namespace Drupal\my_module;
use Symfony\Component\DependencyInjection\ContainerInterface;
class CollectorService {
protected $services;
public function __construct(ContainerInterface $container) {
// Collect all services tagged with "my_tag_name"
$this->services = $container->findTaggedServiceIds('my_tag_name');
}
public function getServices() {
return $this->services;
}
}Common Use Cases:
- Event Subscribers: You can tag services as event subscribers, allowing Drupal to listen for certain events and respond accordingly.
- Plugin Managers: Often plugin managers use tags to collect all plugin implementations.
- Command Services: For custom commands, tagging services allows them to be picked up by Drupal's command system.
In essence, tagging services is a way of organizing and structuring how the service container can group and utilize services, making Drupal's service-oriented architecture more modular and extendable.
Here are several practical examples of using tagged services in Drupal to help better understand their application.
1. Event Subscribers
Tagged services are often used to create event subscribers. For example, if you want to track events such as new content creation or user profile updates, you can create a service and subscribe it to the corresponding event.
Example:
1. Creating an Event Subscriber:
Define a service with the event_subscriber tag in the *.services.yml file:
yaml
services:
my_module.event_subscriber:
class: Drupal\my_module\EventSubscriber\MyEventSubscriber
tags:
- { name: event_subscriber }
2. Event Subscriber Class:
This class will respond to the event, for instance, when a new node is created:
namespace Drupal\my_module\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\node\NodeInterface;
use Drupal\node\NodeEvents;
class MyEventSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
$events[NodeEvents::INSERT][] = ['onNodeInsert'];
return $events;
}
public function onNodeInsert(NodeInterface $node) {
// Action upon node insertion
\Drupal::logger('my_module')->info('New node created: ' . $node->getTitle());
}
}
In this example, the service is tagged as an event_subscriber, allowing Drupal to subscribe it to the NodeEvents::INSERT event.
2. Plugin Discovery
Tagged services can be used for plugin discovery and management. For instance, if you're building a module that adds a new type of plugin (like custom forms or payment gateways), you can use tags to register them automatically.
Example:
1. Defining Plugins with Tags:
In your module, create a plugin and register it using a tag:
yaml
services:
my_module.payment_gateway:
class: Drupal\my_module\Plugin\PaymentGateway\MyPaymentGateway
tags:
- { name: payment_gateway }
2. Plugin Class:
Create a plugin class that implements the plugin interface:
namespace Drupal\my_module\Plugin\PaymentGateway;
use Drupal\my_module\PaymentGatewayInterface;
class MyPaymentGateway implements PaymentGatewayInterface {
public function processPayment($amount) {
// Logic for processing payment
}
}
3. Using a Plugin Manager to Discover Services:
Create a plugin manager that collects all plugins with the payment_gateway tag:
namespace Drupal\my_module;
use Symfony\Component\DependencyInjection\ContainerInterface;
class PaymentGatewayManager {
protected $gateways;
public function __construct(ContainerInterface $container) {
$this->gateways = $container->findTaggedServiceIds('payment_gateway');
}
public function getGateways() {
return $this->gateways;
}
}
3. Creating Middleware
Tagged services can be used to create middleware that processes every request before it reaches the main controller.
Example:
1. Defining Middleware with Tags:
Define middleware as a service with the http_middleware tag:
yaml
services:
my_module.middleware:
class: Drupal\my_module\Middleware\MyMiddleware
tags:
- { name: http_middleware }
2. Middleware Class:
The middleware class should implement the HttpKernelInterface:
namespace Drupal\my_module\Middleware;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class MyMiddleware implements HttpKernelInterface {
protected $httpKernel;
public function __construct(HttpKernelInterface $httpKernel) {
$this->httpKernel = $httpKernel;
}
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true) {
// Request processing logic
if ($request->getPathInfo() == '/custom-path') {
return new Response('Custom response for /custom-path');
}
return $this->httpKernel->handle($request, $type, $catch);
}
}
4. Setting Up Cron Tasks Using Tags
Tagged services can also be used to register cron tasks. This allows you to create tasks that will automatically run when Drupal's cron is executed.
Example:
1. Registering a Cron Task:
In the *.services.yml file, register a service with the cron tag:
yaml
services:
my_module.cron_service:
class: Drupal\my_module\Cron\MyCronService
tags:
- { name: cron }
2. Cron Task Class:
Create a class that implements the logic for the cron task:
namespace Drupal\my_module\Cron;
class MyCronService {
public function run() {
// Execute the cron task logic
\Drupal::logger('my_module')->info('Cron task executed.');
}
}
5. Setting Up Custom Drush Commands
Drush commands can also be registered using tagged services. This makes it easy to add new commands to the existing ones.
Example:
1. Registering a Drush Command with a Tag:
In *.services.yml, register a Drush command:
yaml
services:
my_module.drush_command:
class: Drupal\my_module\Drush\MyDrushCommand
tags:
- { name: drush.command }
2. Command Class:
Create a class that describes the logic of the command:
namespace Drupal\my_module\Drush;
use Drush\Commands\DrushCommands;
class MyDrushCommand extends DrushCommands {
/**
* Execute the "my-custom-command".
*
* @command my-module:custom-command
*/
public function customCommand() {
$this->output()->writeln('My custom Drush command.');
}
}
Conclusion
Tagged services in Drupal greatly simplify the extension of system functionality and allow easy integration of new features through flexible and modular mechanisms. These examples are just a small part of how you can use tagged services to create more powerful and modular applications.
This should give you a clear idea of how tagged services are practically applied in Drupal. Let me know if you'd like to explore any of these examples further!
Comments