Drupal's service container for dependency injection allows modules to register services and parameters to the service container or alter and modify the service container. Usually, this is done with a services.yml
file provided by a module or a service provider for dynamic registration and alteration. But! Did you know you can integrate with Drupal's service container without a module?
Most PHP applications provide a base kernel, and then the application code extends the kernel for registering services. Drupal doesn't follow this pattern as extension and development of Drupal typically happen through modules. It isn't obvious, but it is documented in the globals.api.php
file:
/**
* Allows defining of site-specific service providers for the Drupal kernel.
*
* To define a site-specific service provider class, use code like this:
* @code
* $GLOBALS['conf']['container_service_providers']['MyClassName'] = 'Drupal\My\Namespace\MyClassName';
* @endcode
*
* @see \Drupal\Core\DrupalKernel::$serviceProviderClasses
*/
global $conf;
The global $conf
variable can be used to define site-specific service providers! I have used this trick for some time to carry around various reusable code I like using on my for-fun projects without porting around modules. It is also how I made Retrofit.
There are two places you can register the service provider:
- In your
sites/default/settings.php
- In a file that Composer autoloads
I often prefer the latter option as it's more portable but may be more reasonable for other projects. Retrofit provides a bootstrap.php
file that Composer autoloads and configures its service provider.
<?php
declare(strict_types=1);
use Retrofit\Drupal\Provider;
$GLOBALS['conf']['container_service_providers']['retrofit'] = Provider::class;
That service provider then hooks into Drupal to make Retrofit possible!
Why would I use this over a module? Most times, I wouldn't. But I always like to bend the ways we develop with Drupal.
Want more? Sign up for my weekly newsletter