Home > Backend Development > PHP Tutorial > Drupal 8 Modules - Configuration Management and the Service Container

Drupal 8 Modules - Configuration Management and the Service Container

Christopher Nolan
Release: 2025-02-21 10:17:09
Original
1013 people have browsed it

Drupal 8 Modules - Configuration Management and the Service Container

Core points

    The
  • Drupal 8's ConfigFormBase class provides additional functionality to interact with the configuration system, allowing tools to convert forms to stored values. This can be done by replacing the extension class with ConfigFormBase and making the necessary changes in the form. The configuration in Drupal 8 is stored in a YAML file and can be changed through the UI for deployment across different sites.
  • The service container in Drupal 8 allows the creation of a service, that is, a PHP class that performs global operations, and registers it into the service container for access. Dependency injection is used to pass objects to other objects, ensuring decoupling. You can register a service by creating a demo.services.yml file in the root directory of the module.
  • Dependency injection in Drupal 8 is a design pattern that allows one object to provide dependencies for another, making the code more modular and easier to test. This can be achieved by extending the ControllerBase class or implementing the ContainerInjectionInterface . You can also use the Drupal class to access the service globally.

Note that some code parts may be outdated because Drupal 8 is in development at the time of writing. Please check out this repository, I tried to update the sample code and make it compatible with the latest Drupal 8 version.

In previous articles on Drupal 8 module development, we looked at creating block types and forms. We have seen that blocks are now reusable, and that everything needed to define block types is done in one class. Similarly, form generation functions are also grouped in a class where the tasks performed by a particular method are similar to those we are used to in Drupal 7.

In this tutorial, I will continue from where we ended last time. I'll explain how to convert our DemoForm into a form used to store values ​​through Drupal 8 configuration system. After that, we will illustrate service containers and dependency injection with examples.

Don't forget, if you want to get all the code written in this tutorial series, you can check out this repository.

Configuration form

When we first defined DemoForm, we extended the FormBase class, which is the easiest implementation of FormInterface. However, Drupal 8 also comes with a ConfigFormBase, which provides some additional features that make interacting with the configuration system very easy.

What we have to do now is convert DemoForm into a form that stores the email address entered by the user. The first thing we should do is replace the extension class with ConfigFormBase (and of course use it):

use Drupal\Core\Form\ConfigFormBase;

class DemoForm extends ConfigFormBase {
Copy after login
Copy after login
Copy after login

Before we continue to change the rest of the form, let's take a look at how simple configurations in Drupal 8 work. I said "simple" because there are more complex configuration entities, which we will not introduce today. For now, the configuration provided by the module (core or contrib) is stored in the YAML file. When the module is enabled, this data is imported into the database (to improve performance when used). With the UI, we can change this configuration and then easily export it to a YAML file for deployment across different sites.

The

module can provide a default configuration in the YAML file in the config/install folder in the module root directory. The naming convention for this file is to prefix the module's name. So let's create a file called demo.settings.yml. In this file, let's paste the following:

demo:
  email_address: demo@demo.com
Copy after login
Copy after login

This is a nested structure (like an associative array in PHP). Under the demo key, we have another key-value pair. Typically, to access these nested values, we use dots (.). In our case it is demo.email_address.

Once we have this file, one important thing you need to remember is that this file will be imported only when the module is installed. So, keep reinstalling it. Now we can go back to our form and see one by one the methods that need to be adjusted.

This is what buildForm() Method now looks like:

public function buildForm(array $form, array &$form_state) {

  $form = parent::buildForm($form, $form_state);

  $config = $this->config('demo.settings');

  $form['email'] = array(
    '#type' => 'email',
    '#title' => $this->t('Your .com email address.'),
    '#default_value' => $config->get('demo.email_address')
  );

  return $form;
}
Copy after login
Copy after login

First, contrary to FormBase, the ConfigFormBase class also implements this method in order to add elements to the form array (submit button). So, before adding our own elements, we can use what we did before the parent class.

Now for the configuration section. Drupal 8 provides a Config object that we can use to interact with the configuration. Some classes have obtained it through dependency injection. ConfigFormBase This is such a class.

As you can see, we are using the config() method of the parent class to retrieve a Config object that has been populated with our demo.settings simple configuration. Then, for the #default_value of the email form element, we use the Config method of the get() object to retrieve the value of the email address.

Next we just need to change the commit handler, because the validateForm() method can now remain the same:

public function submitForm(array &$form, array &$form_state) {

  $config = $this->config('demo.settings');
  $config->set('demo.email_address', $form_state['values']['email']);
  $config->save();

  return parent::submitForm($form, $form_state);
}
Copy after login

In this method, we first retrieve the Config object we configured (like we did before). We then use its set() method to change the value of email_address to the user-submitted value. Then we use the save() method to save the configuration. Finally, we extend the parent commit handler because it does include some functionality (in this case it sets the Drupal message to the screen).

That's it. You can clear the cache and give it a try. By submitting a new email address, you store it in the configuration. The demo.settings.yml file will certainly not change, but you can export the demo.settings configuration and import it to another site.

Service container and dependency injection

The next thing we want to look at is the service container. The philosophy behind the service is to break down functionality into reusable components. Therefore, a service is a PHP class that performs some global operations and registers to the service container for access.

Dependency injection is the way we pass objects to ensure decoupling. Each service needs to handle one thing, and if it needs another service, the latter can be injected into the former. But we will see how to do it right away.

Next, we will create a very simple service and register it into the container. It only has one real way to return simple values. We then inject the service as a dependency into our DemoController and use the value provided by the service.

In order to register a service, we need to create a demo.services.yml file located in the root directory of the module, with the following content:

use Drupal\Core\Form\ConfigFormBase;

class DemoForm extends ConfigFormBase {
Copy after login
Copy after login
Copy after login

The file naming convention is module_name.services.yml.

The first line creates an array of services. The second line defines the first service (called demo_service, prefixed by the module name). The third line specifies the class that will be instantiated for this service. Next is to create the src/ class file in the DemoService.php folder of our module. This is what my service does (actually nothing, just to illustrate how to use it):

demo:
  email_address: demo@demo.com
Copy after login
Copy after login

Nothing needs to be explained here, as it is very basic. Next, let's turn to our DemoController and use this service. We can do this in two ways: access the container globally through the Drupal class or pass an object of this class to our controller using dependency injection. Best practice suggests we should take the second approach, so that's what we're going to do. But sometimes you need global access to the service. To do this, you can do the following:

public function buildForm(array $form, array &$form_state) {

  $form = parent::buildForm($form, $form_state);

  $config = $this->config('demo.settings');

  $form['email'] = array(
    '#type' => 'email',
    '#title' => $this->t('Your .com email address.'),
    '#default_value' => $config->get('demo.email_address')
  );

  return $form;
}
Copy after login
Copy after login

Now $service is the object of the DemoService class we just created. But let's see how to inject our service as a dependency in the DemoController class. I'll explain what needs to be done first, and then you'll see a complete controller with all the changes made to it.

First, we need to access the service container. This is very easy for the controller. We can extend the ControllerBase class, which provides us with this in addition to some other helper programs. Alternatively, our controller can implement ContainerInjectionInterface, which also allows us to access the container. But we will stick to ControllerBase, so we need use the class.

Next, we need use Symfony 2 ContainerInterface as a requirement of the create() method, which instantiates another object of the controller and passes the service we want to it.

Finally, we will need a constructor to get the passed service objects (the returned object of create()) and assign them to properties for later use. create() The order in which the method returns objects needs to reflect the order in which they are passed to the constructor.

So let's look at our modified DemoController:

use Drupal\Core\Form\ConfigFormBase;

class DemoForm extends ConfigFormBase {
Copy after login
Copy after login
Copy after login

As you can see, all the steps are here. The create() method creates a new instance of our controller class and passes the service retrieved from the container to it. Finally, an instance of the DemoService class is stored in the $demoService property, which we can use to call its getDemoValue() method. This value will then be used in the "Hello" message. Clear the cache and give it a try. Go to the demo/ path and you should see the "Hello Upchuk!" printed on the page.

I believe you can see the power of the service container, as we can now write decoupled functions and pass them where needed. I'm not showing you how to do it, but you can declare dependencies when registering for a service. This means that when Drupal instantiates a service object, it will do so for all its dependencies, and pass them to its constructor. You can read more about how to do this on this document page.

Conclusion

In this article, we have looked at a lot of cool stuff. We have seen how the configuration system manages simple configurations and what "form" features are provided for this. I encourage you to explore how ConfigFormBase is implemented and what features are available when extending it. Additionally, you should practice using import/export configurations between sites in the UI. From now on, this will be a big improvement to the deployment process.

We then looked at the services, what they are, and how they work. A great way to maintain reusable and decoupled functional blocks that are accessible from anywhere. I hope the concept of dependency injection is no longer as scary (if it is for you). It is basically the same as passing parameters to procedural functions, but is done behind the scenes by Symfony and its powerful service containers using constructor methods (or setters).

Frequently Asked Questions about Building Drupal 8 Modules: Configuration Management and Service Containers

What is the role of service containers in Drupal 8?

The service container in Drupal 8 is a key component that manages the creation of services, objects that are used globally in Drupal applications. It ensures that each service is instantiated only once, saving memory and improving performance. The service container also handles dependency injection, a design pattern that allows one object to provide dependencies for another object. This makes the code more modular, easier to test and promotes better organization.

How to define a new service in Drupal 8?

To define a new service in Drupal 8, you need to create a services.yml file in the root directory of the module. This file should contain the name, class, and parameters of the service. This class should be the fully qualified name of the class that implements the service, and the parameters should be any service or parameters on which the service depends.

What is the purpose of configuration management in Drupal 8?

Configuration Management in Drupal 8 is a system that allows you to manage site configuration data in a consistent manner. It allows you to import, export, and synchronize configuration data, which is useful when moving configuration changes from the development environment to the production site. It also provides a way to track and manage site configuration changes over time.

How to export and import configuration data using the configuration management system?

To export configuration data in Drupal 8, you can use the Configuration Management interface in the Admin Panel or use the Drush command. The exported data will be in YAML format and can be read and edited easily. To import configuration data, you can upload the exported YAML file through the configuration management interface or use the Drush command. Remember to back up your site before importing configuration data to prevent any potential data loss.

What is dependency injection and why is it important in Drupal 8?

Dependency injection is a design pattern that allows one object to provide dependencies for another object. In Drupal 8, it is used to make services and controllers more modular and easier to test. Instead of creating dependencies inside an object, they are passed (injected) through a constructor or setter method. This makes the code easier to test, more flexible and less coupled.

How to inject dependencies into my Drupal 8 service?

To inject dependencies into services in Drupal 8, you need to define them in the definition of services in the services.yml file. Dependencies should be listed under the arguments key. When a service is created, the service container will automatically pass these dependencies to the service's constructor.

What is the difference between services and plug-ins in Drupal 8?

In Drupal 8, a service is an object that performs global tasks in an application, while a plug-in is an object that performs specific tasks in a pluggable manner. Services are defined in the services.yml file and managed by the service container, while plug-ins are discovered and instantiated by the plug-in manager.

How to override services in Drupal 8?

To overwrite a service in Drupal 8, you need to define a service with the same name as the service you want to overwrite in the services.yml file of the module. Your new service should extend the original service's class and override the method you want to change.

How to use the configuration management system to track changes in site configuration?

The configuration management system in Drupal 8 provides a way to track site configuration changes through a configuration snapshot system. This system takes a snapshot of the site's active configuration whenever you import or synchronize configuration data. You can then compare these snapshots to see what changes have been made.

services.yml What does a file do in Drupal 8?

The services.yml file in Drupal 8 is the place where module services are defined. Each service is defined using a unique name, a fully qualified name of the class that implements the service, and any service or parameters the service depends on. services.yml Files are read by the service container, and the service container manages the creation and injection of the service.

The above is the detailed content of Drupal 8 Modules - Configuration Management and the Service Container. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template