Статьи

Создание пользовательских плагинов cTools в Drupal 7

cTools — один из тех критических модулей Drupal 7, от которых зависят многие другие. Он предоставляет множество API и функций, которые облегчают жизнь при разработке модулей. Представления и панели являются лишь двумя примерами таких мощных электростанций, которые зависят от него.

cTools делает доступными различные виды функциональности. Кэширование объектов , экспорт конфигурации, мастера форм, диалоги и плагины — это лишь некоторые из них. Большая часть заслуг, которые вы обычно относите к представлениям или панелям, фактически принадлежит cTools.

Drupal logo

В этой статье мы рассмотрим плагины cTools, особенно то, как мы можем создавать свои собственные. После краткого введения мы сразу же приступим к работе с пользовательским модулем, который будет использовать плагины cTools, чтобы сделать определение блоков Drupal более приятным (более подробно, как мы их определяем в Drupal 8).

Вступление

Плагины cTools в Drupal 7 (концептуально не очень отличающиеся от системы плагинов в Drupal 8) предназначены для легкого определения многократно используемых функциональных возможностей. То есть за способность определять изолированную бизнес-логику, которая используется в некотором контексте . Цель состоит в том, чтобы один раз установить этот контекст и тип плагина, а затем позволить другим модулям определять плагины, которые могут автоматически использоваться в этом контексте .

Если вы разрабатывали сайты на Drupal более года, вы, вероятно, встречали плагины cTools в одной форме или форме. Я думаю, что первым типом плагина, с которым мы обычно имеем дело, является плагин content_type который позволяет нам создавать собственные панели панелей, отображающие динамический контент. И это потрясающе. Некоторые из других, с которыми вы, возможно, столкнулись в одной и той же области панелей, — это, вероятно, context и access (правила видимости). Может быть, даже relationships и arguments . Все это предоставлено cTools. Панели добавляются в этот список путем введения layouts и styles которые мы обычно используем для создания макетов панелей и отдельных стилей панелей. Это, я думаю, более распространенные.

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

Окончательный код (+ немного больше) можно найти в этом хранилище, если вы хотите следовать. И я надеюсь, что вы знакомы с шагами, необходимыми для определения пользовательских блоков Drupal .

Модуль block_plugin

Как я уже упоминал, я хотел бы проиллюстрировать мощь плагинов cTools с пользовательским типом плагинов, который делает определение блоков Drupal 7 более разумным. Вместо реализации 2 основных хуков ( hook_block_info() и hook_block_view() ), необходимых для определения блока, мы сможем иметь отдельные файлы плагинов, каждый из которых отвечает за всю логику, связанную с их собственным блоком. Больше не нужно переключать регистры и менять реализацию хука каждый раз, когда нам нужен новый блок. Итак, как мы это сделаем?

Сначала давайте создадим наш файл block_plugin.info чтобы начать работу с нашим модулем:

 name =   Block   Plugin description =   Using  cTools plugins to define Drupal  core blocks core =   7.x dependencies []   =  ctools 

Достаточно просто.

Тип плагина

Чтобы определить тип нашего новостного плагина, внутри файла block_plugin.module нам нужно реализовать hook_ctools_plugin_type() который отвечает за определение новых типов плагинов, которые cTools будет распознавать:

 function  block_plugin_ctools_plugin_type ()   { 
   return  array ( 
     'block'   =>  array ( 
       'label'   =>   'Block' , 
       'use hooks'   =>  FALSE , 
       'process'   =>   'block_plugin_process_plugin' 
     ) 
   ); 
 } 

В этом хуке нам нужно вернуть ассоциативный массив всех определений типов плагинов, которые нам нужны по имени машины с именем типа плагина. Сегодня мы создаем только один названный block . Для получения дополнительной информации обо всех доступных здесь опциях, не стесняйтесь обращаться к файлу помощи plugins-creating.html creation.html в модуле cTools. Бесполезно повторять всю эту информацию здесь.

Ключ process определяет имя функции, которое запускается каждый раз, когда cTools загружает для нас плагин и отвечает за формирование или массирование данных плагина перед его использованием. Это своего рода вспомогательная функция, которая каждый раз подготавливает плагин для нас, поэтому нам не нужно об этом беспокоиться. Итак, давайте посмотрим, что мы можем сделать внутри этой функции:

 function  block_plugin_process_plugin (& $plugin ,  $info )   { 
   // Add a block admin title 
   if   (! isset ( $plugin [ 'admin title' ]))   { $exploded =  explode ( '_' ,  $plugin [ 'name' ]); $name =   '' ; 
     foreach   ( $exploded as  $part )   { $name .=  ucfirst ( $part )   .   ' ' ; 
     } $plugin [ 'admin title' ]   =  $name ; 
   } 

   // By default we also show a block title but this can be overwritten 
   if   (! isset ( $plugin [ 'show title' ]))   { $plugin [ 'show title' ]   =  TRUE ; 
   } 

   // Add a block view function 
   if   (! isset ( $plugin [ 'view' ]))   { $plugin [ 'view' ]   =  $plugin [ 'module' ]   .   '_'   .  $plugin [ 'name' ]   .   '_view' ; 
   } 

   // Add a block form function 
   if   (! isset ( $plugin [ 'configure' ]))   { $plugin [ 'configure' ]   =  $plugin [ 'module' ]   .   '_'   .  $plugin [ 'name' ]   .   '_configure' ; 
   } 

   // Add a block save function 
   if   (! isset ( $plugin [ 'save' ]))   { $plugin [ 'save' ]   =  $plugin [ 'module' ]   .   '_'   .  $plugin [ 'name' ]   .   '_save' ; 
   } 
 } 

Этот обратный вызов получает массив плагинов в качестве ссылки и некоторую информацию о типе плагина. Задача под рукой — динамически изменять или добавлять данные в плагин. Так чего же мы достигаем выше?

Во-первых, если разработчик не определил заголовок администратора для блочного плагина, мы генерируем его автоматически на основе имени компьютера плагина. Это так, что у нас всегда есть заголовок администратора в интерфейсе блока Drupal.

Во-вторых, мы выбираем всегда отображать заголовок блока, поэтому помечаем ключ show title массива плагинов как ИСТИНА. Определяя плагин для блоков, разработчик может установить для него значение FALSE, в этом случае мы не будем показывать заголовок блока (тему).

В-третьих, четвертом и пятом мы генерируем функцию обратного вызова для просмотра блока, сохраняем и настраиваем действия (если они еще не были установлены разработчиком для данного плагина). Эти обратные вызовы будут использоваться при реализации hook_block_view() , hook_block_configure() и hook_block_save() соответственно. Мы не будем рассматривать последние два в этой статье, но не стесняйтесь проверить репозиторий, чтобы увидеть, как они могут выглядеть.

И это почти все, что нам нужно для определения нашего пользовательского типа плагина. Однако мы должны также реализовать hook_ctools_plugin_directory() которая, как вы, возможно, знаете, отвечает за указание cTools, где в текущем модуле находится плагин определенного типа:

 function  block_plugin_ctools_plugin_directory ( $module ,  $plugin )   { 
   if   ( $module ==   'block_plugin'   &&  in_array ( $plugin ,  array_keys ( block_plugin_ctools_plugin_type ()))   )   { 
     return   'plugins/'   .  $plugin ; 
   } 
 } 

Это должно быть реализовано также любым другим модулем, который хочет определить block плагины.

Drupal блоки

Теперь, когда у нас есть тип плагина, давайте напишем код, который превращает любой определенный плагин block в блок Drupal. Начнем с реализации hook_block_info() :

 function  block_plugin_block_info ()   { $blocks =  array (); $plugins =  block_plugin_get_all_plugins (); 
   foreach   ( $plugins as  $plugin )   { $blocks [ DELTA_PREFIX .  $plugin [ 'name' ]]   =  array ( 
       'info'   =>  $plugin [ 'admin title' ], 
     ); 
   } 

   return  $blocks ; 
 } 

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

Мы знаем, что каждый плагин будет иметь имя компьютера (в основном, имя включаемого файла) и admin title потому что мы генерируем его на этапе обработки, если он не существует. DELTA_PREFIX — это простая константа, в которой мы определяем префикс, который мы хотим для имени машины блока, потому что нам нужно повторно использовать его и иметь возможность легко изменить его, если мы хотим:

 define ( 'DELTA_PREFIX' ,   'block_plugin_' ); 

Наша вспомогательная функция, которую мы видели ранее, выглядит так:

 function  block_plugin_get_all_plugins ()   { 
   return  ctools_get_plugins ( 'block_plugin' ,   'block' ); 
 } 

Это простая оболочка для соответствующей функции cTools. И в этом отношении у нас также есть следующая функция, отвечающая за загрузку одного плагина по имени его машины:

 function  block_plugin_get_plugin ( $name )   { 
   return  ctools_get_plugins ( 'block_plugin' ,   'block' ,  $name ); 
 } 

Это очень похоже на предыдущее.

Чтобы наши определения блоков в Drupal были завершены, нам нужно реализовать hook_block_view() :

 function  block_plugin_block_view ( $delta =   '' )   { $plugin =  block_plugin_plugin_from_delta ( $delta ); 
   if   (! $plugin )   { 
     return ; 
   } $block =  array (); 

   // Optional title 
   if   ( isset ( $plugin [ 'title' ])   &&  $plugin [ 'show title' ]   !==  FALSE )   { $block [ 'subject' ]   =  $plugin [ 'title' ]; 
   } 

   // Block content $block [ 'content' ]   =  $plugin [ 'view' ]( $delta ); 

   return  $block ; 
 } 

Так что здесь происходит?

Во-первых, мы используем другую вспомогательную функцию, чтобы попытаться загрузить плагин на основе дельты текущего блока и ничего не делать, если мы не имеем дело с блоком плагинов.

Во-вторых, мы строим блок. Если пользователь указал ключ title в плагине, и ключ show title не является ложным, мы устанавливаем тему блока (его заголовок в основном) в качестве значения первого. Что касается фактического содержимого блока, мы просто вызываем обратный вызов представления, определенный в плагине. Вот и все.

Давайте быстро рассмотрим также вспомогательную функцию, отвечающую за загрузку плагина на основе дельты блока:

 function  block_plugin_plugin_from_delta ( $delta )   { $prefix_length =  strlen ( DELTA_PREFIX ); $name =  substr ( $delta ,  $prefix_length ); $plugin =  block_plugin_get_plugin ( $name ); 
   return  $plugin ?  $plugin :  FALSE ; 
 } 

Ничего сложного здесь не происходит.

Определение блочных плагинов

Поскольку мы сказали cTools, что он может найти block плагины внутри папки plugins/block нашего модуля, давайте продолжим и создадим эту папку. В нем мы можем добавить наш первый блок в файл с расширением .inc , например my_block.inc :

 <? php $plugin =  array ( 
   'title'   =>  t ( 'This is my block' ), 
 ); 

 /** * Returns a renderable array that represents the block content */ 
 function  block_plugin_my_block_view ( $delta )   { 
   return  array ( 
     '#type'   =>   'markup' , 
     '#markup'   =>   'Yo block!' 
   ); 
 } 

Как мы делаем со всеми другими плагинами ( content_type , context и т. Д.), Определение плагина находится в форме массива внутри переменной с именем $plugin . И для нашего случая все, что нам нужно на данный момент — это title (и даже не потому, что без него блок просто не будет показывать заголовок).

Ниже мы определили нашу функцию обратного вызова для отображения блока. Наименование этой функции важно. Он соответствует шаблону, который мы использовали для него на этапе обработки ( module_name_plugin_name_view ). Если мы хотим назвать его по-другому, все, что нам нужно сделать, это сослаться на имя функции в ключе представления $plugin и он будет использовать его вместо этого.

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

Вывод

В этой статье мы немного поговорили о плагинах cTools и увидели, как мы можем определить наш собственный тип плагина. Мы использовали последний для преобразования блочной системы Drupal в элементарную систему плагинов. Это может быть расширено, чтобы также позволить замену связанных с блоком хуков обратными вызовами внутри подключаемого файла плагина. Кроме того, как упоминалось ранее, вы также можете убедиться, что все данные, доступные в hook_block_info() могут быть определены внутри плагина. Я оставляю эти задачи на ваше усмотрение.