Creating Drush 9 commands and porting legacy commands

14 Okt 2017
Drush 9

Upgrading to Drush 9

Drush should be installed and updated through composer. There is no stable Drush 9 version yet, so the development version must be used. Updating to the development version of Drush 9 is a simple as typing:

composer require drush/drush:dev-master

Porting your Drush commands to Drush 9

Porting the commands is a semi-automatic process: There is a command that will generate the required files and class structure for you. To start the wizard, just type:

drush generate drush-command-file -l dev

Drush will ask you for the module's machine name and for the optional path to the legacy Drush command file (the one that has your commands, ending with .drush.inc). You will have to provide the absolute path.

drush.services.yml

This is the file your Drush command definition goes into. Do not use your module's regular services.yml as you might have done in Drush 8 or else you will confuse the legacy Drush which will lead to a PHP error like this:

Fatal error: Class 'Drush\Commands\DrushCommands' not found in MyModuleCommands.

Use the dedicated drush.services.yml file in your module's root directory instead.

The file should look like this:

  1. services:
  2. mymodule.commands:
  3. class: \Drupal\mymodule\Commands\MyModuleCommands
  4. tags:
  5. - { name: drush.command }

As in other symfony service definitions, you can (and should) provide other services as arguments DI style and do all the other crazy stuff.

MyModuleCommands.php

  1. namespace Drupal\mymodule\Commands;
  2.  
  3. use Drush\Commands\DrushCommands;
  4.  
  5. /**
  6.  *
  7.  * In addition to a commandfile like this one, you need a drush.services.yml
  8.  * in root of your module.
  9.  *
  10.  * See these files for an example of injecting Drupal services:
  11.  * - http://cgit.drupalcode.org/devel/tree/src/Commands/DevelCommands.php
  12.  * - http://cgit.drupalcode.org/devel/tree/drush.services.yml
  13.  */
  14. class MyModuleCommands extends DrushCommands {
  15.  
  16. /**
  17.   * @command mymodule:do-something
  18.   * @param array $options An associative array of options whose values come from cli, aliases, config, etc.
  19.   * @validate-module-enabled mymodule
  20.   * @aliases mm:do-something, mm:ds, mymodule-do-something
  21.   */
  22. public function generate()
  23. {
  24. // See bottom of https://weitzman.github.io/blog/port-to-drush9 for details on what to change when porting a
  25. // legacy command.
  26. }
  27.  
  28.  
  29. }

 

As seen above, the generate() method needs to be implemented manually. Other manual changes may include creating a constructor in case other services are injected.

Drush 9 mimics symfony's style module:command naming structure and this should be respected. I don't see any reson not to include the legacy command as an alias however: If your command used to be my_module:do-something, use my-module:do-something in @command, but also the old my_module-do-something as @alias as presented in the example above. This way scripts calling the old Drush will continue working.

Maintaining Drush 8, Drush 9 and Drupal Console commands side by side

The new three standards of managing Drupal through a shell should not be an excuse for bad practice. To avoid code duplication, make sure your module defines a service which holds all the business logic that can be run by any of the above tools.

Simple XML Sitemap (project page) now supports Drush 9 and is a good example of this principle:

simple_sitemap.drush.inc (Drush 8)

  1. /**
  2.  * @file
  3.  * Drush (< 9) integration.
  4.  */
  5.  
  6. /**
  7.  * Implements hook_drush_command().
  8.  */
  9. function simple_sitemap_drush_command() {
  10. $items['simple_sitemap-generate'] = [
  11. 'description' => 'Regenerate the XML sitemap according to the module settings.',
  12. 'callback' => 'drush_simple_sitemap_generate',
  13. 'drupal dependencies' => ['simple_sitemap'],
  14. ];
  15. return $items;
  16. }
  17.  
  18. /**
  19.  * Callback function for hook_drush_command().
  20.  *
  21.  * Regenerate the XML sitemap.
  22.  */
  23. function drush_simple_sitemap_generate() {
  24. \Drupal::service('simple_sitemap.generator')->generateSitemap('drush');
  25. }

SimplesitemapCommands.php (Drush 9)

  1. namespace Drupal\simple_sitemap\Commands;
  2.  
  3. use Drupal\simple_sitemap\Simplesitemap;
  4. use Drush\Commands\DrushCommands;
  5.  
  6. /**
  7.  * Class SimplesitemapCommands
  8.  * @package Drupal\simple_sitemap\Commands
  9.  */
  10. class SimplesitemapCommands extends DrushCommands {
  11.  
  12. /**
  13.   * @var \Drupal\simple_sitemap\Simplesitemap
  14.   */
  15. protected $generator;
  16.  
  17. /**
  18.   * SimplesitemapCommands constructor.
  19.   * @param \Drupal\simple_sitemap\Simplesitemap $generator
  20.   */
  21. public function __construct(Simplesitemap $generator) {
  22. $this->generator = $generator;
  23. }
  24.  
  25. /**
  26.   * Regenerate the XML sitemap according to the module settings.
  27.   *
  28.   * @command simple-sitemap:generate
  29.   * @validate-module-enabled simple_sitemap
  30.   * @aliases ss:generate, ssg, simple_sitemap:generate, simple_sitemap-generate
  31.   */
  32. public function generate() {
  33. $this->generator->generateSitemap('drush');
  34. }
  35.  
  36. }

All of the business logic of this command is inside of the method generateSitemap() of the simple_sitemap service.

Downgrading back to Drush 8

Not a fan of changing APIs? Downgrading is a composer command away:

composer require drush/drush:^8.0

Conclusion

It is good to see the Drush project keeping up with time and pubishing Drush 9 parallely to the appearance of Drupal 8.4.0. The API changes are the necessary price we pay for a modern and continuously evolving framework like Drupal.

Feel free to leave a comment below in case of questions or new Drupal 8.4 / Drush 9 insigts.

Neuen Kommentar schreiben

Der Inhalt dieses Feldes wird nicht öffentlich zugänglich angezeigt.

Restricted HTML

  • Zulässige HTML-Tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h4 id> <h5 id> <h6 id>
  • HTML - Zeilenumbrüche und Absätze werden automatisch erzeugt.
  • Web page addresses and email addresses turn into links automatically.

Angebot innerhalb von 24 Stunden

Ob ein großes kommerzielles System, oder eine kleine Business Seite, wir schicken ein Angebot ab innerhalb von 24 Stunden nachdem Sie diese Taste drücken: Angebot anfordern