Drupal 9 is rapidly approaching with a release planned, at the time of writing this blog, of June 3, 2020. In addition to much anticipated updates to core (use of Symfony 4.4), there also comes the removal of a ton of deprecated code. This blog will help you prepare for Drupal 9 with answers to your most pressing questions like:

  • Why is code being deprecated? 

  • How will the release of Drupal 9 affect my site? 

  • What's the best way to update a Drupal contrib module to work with Drupal 9? 

Deprecating Code

What is deprecated code? Simply put, code becomes depreciated when it is no longer the best way to achieve the original goal. We deprecate code instead of outright deleting it to provide backwards compatibility and to make sure we don’t release code that breaks sites.

If you have spent any time programming in Drupal 8, I am sure you have found yourself using strategies available to you in Drupal 7, take Node::load() for example. If you go to the API docs you will see a warning that this method is deprecated and will be removed in Drupal 9. Under the hood, Node::load() uses the Drupal 8 EntityTypeManager to get the node storage and load it which is the accepted way to do it. Deprecating and removing deprecated code should be seen as a healthy sign of an open source project as it proves progress is being made to keep it fresh with the latest best practices. 

How This Will Impact You

What does this mean for module developers and site maintainers? Fortunately, if your site works for Drupal 8.9.x it will work for 9.x as the only change between the releases is the removal of deprecated code. After updating to 8.9.x, you’ll want to update each contrib module currently installed on your site. Even so, the best way to be 100% confident your site is Drupal 9 ready is to use the drupal checker command line tool to scan your custom and contrib code. 

How to Install and Run Drupal-Check  

To run the drupal checker  on your project, use composer to install it, and run it in the directory you want to scan:

composer global require mglaman/drupal-check
cd path/to/module/to/test
drupal-check *

This will print a report that you can share with your internal development team, or if it is in regards to a contrib module, make a patch and fix it yourself.

Making a Contrib Module Ready for Drupal 9

Now that we know about the awesome drupal-checker CLI tool, we are going to use it to make sure one of our favorite modules, YAML Content, is Drupal 9 ready. YAML content already has an open Drupal 9 readiness issue, but if you have to create a new one, the issue should look something like this:

Note how we’ve added the project name to the title and added the issue tag of “Drupal 9 compatibility”, this will make it easier to find in the issue queue.  

If you are new to contributing or just looking for an easy way to set up a local development environment, take a look at my previous blog, Get Drupal 8.6 Running Locally in 5 Steps.  

These are the steps we are going to follow:

  1. Start with Drupal 8.8.x or 8.9.x
  2. Install/update drupal-check:
  3. $ composer global require mglaman/drupal-check
  4. Download module using git:
  5. $ git clone git@git.drupal.org:project/yaml_content.git
  6. Run drupal-check:
  7. $ drupal-check *
  8. Update the info.yml file(s) (remember that some projects include more than one module!) by removing the “core:” line and adding this one in its place:
  9. core_version_requirement: ’^8 || ^9’
  10. Fix all deprecations that are reported.
  11. Upload patch(es).

Drupal-check will print out the file, line number, deprecation message and the total number of errors. At this time, we have 11 errors for yaml_content:

Writing a Patch to Fix Deprecated Code

While patching the issue it is important that we follow best practices and use dependency injection rather than calling the drupal service container. Luckily this patch has two different examples of dependency injection, one via service.

yaml_content.service.yml
services:
  ...
  yaml_content.load_helper:
    class: Drupal\yaml_content\Service\LoadHelper
    arguments:
      - '@yaml_content.content_loader'
      - '@logger.channel.yaml_content'
      - '@string_translation'
      - '@file_system'
      - '@messenger'
src/Service/LoadHelper.php
/**
   * @var \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger.
   */
  protected $messenger;

  /**
   * Constructs the load helper service.
   *
   * @param \Drupal\yaml_content\ContentLoader\ContentLoaderInterface $content_loader
   *   The content loader service to use for content imports.
   * @param \Drupal\Core\Logger\LoggerChannelInterface $logger
   *   The logging channel for recording import events.
   * @param \Drupal\Core\StringTranslation\TranslationInterface $translation
   *   String translation service for message logging.
   * @param \Drupal\Core\File\FileSystemInterface $file_system
   *   The file system.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger.
   */
  public function __construct(ContentLoaderInterface $content_loader, LoggerChannelInterface $logger, TranslationInterface $translation, FileSystemInterface $file_system, MessengerInterface $messenger) {
    $this->loader = $content_loader;
    $this->logger = $logger;
    $this->fileSystem = $file_system;
    $this->messenger = $messenger;

    $this->setStringTranslation($translation);
  }

This allows us to replace drupal_set_message() with $this->messenger->addMessage().

For an example of dependency injection within a plugin, take a look at File.php in the patch attached to the issue.

While preparing modules for Drupal 9 readiness it is equally important to update the tests. The drupal-check command found failures in the test files but that is only for known existing deprecation in Drupal8 and PHPUnit 4, not the new dependency injection we added. We’ve touched LoadHelper.php and File.php which both have tests.  If you are unfamiliar with writing automated tests, there’s no better time to learn than now. However, it is my opinion that you push up the patch first and tag the issue with needs review. This will kick off the tests on Drupal.org and you may get help writing tests from the community. 

Conclusion

In this blog we’ve reviewed why Drupal 9 is removing deprecated code, how to create an issue for a contrib module, how to install and run drupal-check and how to write a patch to fix deprecated code. Now is the best time to start testing and getting your site ready for Drupal! Here are some extra resources that may help you get you started: