Создание drush-команд

28.06.2013
Share on FacebookShare on TwitterShare on GooglePlusShare on Linkedin
Автор:

Опытные друпал-разработчики не представляют своей работы без утилиты Drush (Drupal shell), ведь с её помощью большинство рутинных дейстивий в друпале выполняются намного быстрее. Перечень стандартных drush-команд, таких как установка модулей, создание дампа базы, сброс пароля для админа и т.д., можно посмотреть на сайте http://drush.ws/. Тем не менее, часто возникает желание (или необходимость) добавить свою команду. Как это сделать мы и рассмотрим в данной статье.

Возьмём пример: нам нужно создать команду, которая будет удалять все материалы конкретного типа контента. Думаю, многие сталкивались с подобной задачей. Забегая наперёд скажу, что синтаксис команды будет следующим: drush delete-content %content_type%, где %content_type% - машинное имя типа контента.

Создание drush-команды включает в себя три этапа:

  • создание файла example_drush.drush.inc
  • вызов hook_drush_command() в созданном файле
  • описание команд

Создание файла example_module.drush.inc

Обычно это происходит при написании нового модуля: создаём файлы example_drush.info и example_drush.module. Основной файл модуля может быть пустым, но он должен быть включён для корректной работы  drush-команды. Далее создаём командный файл example_drush.drush.inc. Окончание  файла объязательно должно содержать "drush.inc" - это для того, чтобы утилита распознала его как содержащий drush-команды. Drush ищет командные файлы в следующих папках:

  • папка /путь/к/drush/commands
  • папки, перечисленные в опции "include"
  • общесистемная папка командных файлов drush. например - /usr/share/drush/commands
  • папка ".drush" в домашней папке пользователя
  • sites/all/drush в текущей инсталляции друпала
  • папки включённых модулей

Вызов hook_drush_command() в созданном файле

Самая важная часть командного файла h - hook_drush_command(). В нём мы описываем сами команды и то, как они будут работать. Описание команд чем-то похоже на описание элементов, используемых в hook_menu. Рассмотрим основные компоненты:

  • aliases - список сокращенных названий команд. Например, вместо использования длинной команды "pm-download", можно использовать "dl". При наличии синонимов, "длинная" комманда все равно будет работать.
  • callback - имя функции, которая будет вызвана для выполнения команды. Имя функции должно начинаться с названия файла. В нашем случае - это example_drush_. Параметр опционален. При его отсутствии drush_invoke() создаст имя сам.
  • description - описание команды.
  • arguments - массив параметров, понимаемых функцией. Используется только для команды "drush help".
  • required-arguments - по умолчанию установлено в FALSE. При установке в TRUE - параметры будут обязательны.
  • drupal dependenices - друпал модули, которые должны быть включены.
  • drush dependencies - drush-файлы, необходимые для выполнения команды.
  • bootstrap - фаза загрузки друпала, с которой будет работать команда.

Так выглядит hook_drush_command() для нашего случая:

 /**
 * Implements hook_drush_command().
 */
function example_drush_drush_command() {
  $items = array();
  $items['delete-content'] = array(
    'description' => 'Delete test content',
    'drupal dependencies' => array('example_drush'),
    'aliases' => array('dc'),
    'arguments' => array(
      'type' => 'Nodes of this type will be deleted',
    ),
  );
  return $items;
} 

Описание выполнения комманды

Функция, которая описывает выполнение команды, в нашем случае, будет выглядеть следующим образом: 

/**
 * Deletes content of specific type.
 */
function drush_example_drush_delete_content($type) {
  if ($type) {
    $nids = db_query("SELECT nid FROM {node} WHERE type = :type", array(':type' => $type))->fetchCol();
    if ($nids) {
      $deleted = 0;
      foreach ($nids as $nid) {
        node_delete($nid);
        $deleted++;
        _drush_print_progress($deleted / count($nids));
      }
      $message = $deleted ? t('Quantity of deleted "@type" nodes: !qty', array('!qty' => $deleted, '@type' => $type)) : t('There are no nodes of type "@type"', array('@type' => $type));
    }
    else {
      $message = t('There are no nodes of specified content type.');
    }
    drush_print($message);
  }
  else {
    drush_print(t('Specify content type'));
  }
}

Для вызова новосозданной команды нужно в терминале ввести "drush delete-content %content_type%" либо  "drush dc %content_type%", где %content_type% - машинное имя типа контента.

Перед и после выполнения drush-команды вызывается последовательность служебных функций. Перечень возможных вариантов можно посмотреть здесь. В нашем примере рассмотрим выполнение функции валидации:

 /**
 * Validate handler for delete-content command.
 */
function drush_example_drush_delete_content_validate($type) {
  $types = node_type_get_types();
  if ($type && !in_array($type, array_keys($types))) {
    return drush_set_error('error', t('Content type "@type" is not exists', array('@type' => $type)));
  }
} 

Таким образом команда будет выполнятся только в случае, если указан существующий тип контента.

Так как на сайте может быть много материалов и, соответственно, команда будет выполняться долго, нам нужно пользователю дать понять, что все идёт по плану и контент удаляется. Для этого выведем "прогресс-бар", с помощью функции _drush_print_progress(): 

 /**
 * Provides progress bar.
 */
function _drush_print_progress($ratio) {
  $percentage = floor($ratio * 100) . '%';
  $columns = drush_get_context('DRUSH_COLUMNS', 80);
  // Subtract 8 characters for the percentage, brackets, spaces and arrow.
  $progress_columns = $columns - 8;
  // If ratio is 1 (complete), the > becomes a = to make a full bar.
  $arrow = ($ratio < 1) ? '>' : '=';
  // Print a new line if ratio is 1 (complete). Otherwise, use a CR.
  $line_ending = ($ratio < 1) ? "\r" : "\n";

  // Determine the current length of the progress string.
  $current_length = floor($ratio * $progress_columns);
  $progress_string = str_pad('', $current_length, '=');

  $output  = '[';
  $output .= $progress_string . $arrow;
  $output .= str_pad('', $progress_columns - $current_length);
  $output .= ']';
  $output .= str_pad('', 5 - strlen($percentage)) . $percentage;
  $output .= $line_ending;

  print $output;
} 

Более подробную информацию можно почерпнуть здесь.

example_drush.tar_.gz
1 vote, Rating: 5
Share on FacebookShare on TwitterShare on GooglePlusShare on Linkedin

Также по теме

1

Ни для кого не секрет, что Google Analytics (далее - GA) - мощнейший инструмент для сбора данных о действиях...

2

В данной статье будет рассказано о том, как быстро настроить модуль Search API и...

3

Наша компания очень часто использует модуль Panels для построения сайтов. Хоть это решение добавляет немало...

4

Queue API — специальный функционал в Drupal, который позволяет формировать очередь и контролировать выполнение трудоемких операций на сайте. В отличии от Batch API, Queue...

5

Бывают задачи, для решения которых необходимо создавать свою таблицу в базе данных и потом своими же запросами взаимодействовать с этой таблицей. В таких случаях написание многочисленных запросов...

Need a quote? Let's discuss the project

Are you looking for someone to help you with your Drupal Web Development needs? Let’s get in touch and discuss the requirements of your project. We would love to hear from you.

Join the people who have already subscribed!

Want to be aware of important and interesting things happening? We will inform you about new blog posts on Drupal development, design, QA testing and more, as well news about Drupal events.

No charge. Unsubscribe anytime