УрокРендер массивов в седьмом Друпале

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

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

Что такое рендер?

Касательно Друпала, рендер обозначает преобразование рендер массивов в HTML код.

Что такое рендер массив?

Рендер массив – классический структурированный массив в Drupal, который предоставляет информацию/данные (возможно, вложенную) наряду с подсказками относительно того, как этот элемент должен быть представлен (например, #type определяет тип элемента).

Массив страницы может выглядеть следующим образом:

$page = array(
  '#show_messages' => TRUE,
  '#theme' => 'page',
  '#type' => 'page',
  'content' => array(
    'system_main' => array(...),
    'another_block' => array(...),
    '#sorted' => TRUE,
  ),
  'sidebar_first' => array(
    ...
  ),
  'footer' => array(
    ...
  ),
  ...
);

Для чего это делается?

До выхода Друпал 7 можно было запросто изменять формы (с помощью hook_form_alter()), однако остальные элементы, которые можно было изменять в модулях или темах, превращались в HTML код до того, как передавались для изменений.

Начиная с седьмого Друпала модуль или тема может использовать hook_page_alter(), чтобы изменить структуру или содержание страницы в самый последний момент. Это означает, что несколько строк PHP кода в теме могут разместить блок в том месте страницы, где вам это необходимо.

Изменение элементов

После выхода седьмого Друпала блоки и страницы могут быть изменены так же, как раньше мы меняли формы. Многие другие элементы также стали доступны для изменения. Например, с помощью hook_page_alter() вы можете в своём модуле или теме сделать так:

function ИМЯМОДУЛЯ_page_alter(&$page) {
  // Пененосим форму поиска из левой колонки в футер
  $page['footer']['search_form'] = $page['sidebar_first']['search_form'];
  unset($page['sidebar_first']['search_form']);
 
  // Убираем блок "Powered by Drupal"
  unset($page['footer']['system_powered-by']);
}

Как рендерные массивы связаны с элементами?

В модулях можно определять новые элементы, которые на самом деле являются рендерными массивами, записанными по определённым правилам. Для этого используется hook_element_info(). Элемент – это рендерный массив, который имеет #type и другие свойства, определяющие его дальнейшее поведение. Когда создаётся рендерный массив и ему задан #type, то к нему подгружаются значения по умолчанию для тех атрибутов, которых нет в массиве, но они описаны в hook_element_info() для этого элемента.

Создание данных в виде рендерных массивов

В Drupal 7, в отличие от прошлых версий, модуль практически всегда создает данные в виде рендерных массивов. Функция вызова любой страницы возвращает массив, который в дальнейшем будет отрендерен (превращён в HTML). Это позволяет модулям хранить данные в массивах настолько долго, насколько это возможно в процессе создания страницы.

В Drupal 6 использовался метод рендеринга данных и их сбора в виде HTML:

function mymodule_menu() {
  $items['mypage-html'] = array(
    'title' => 'Страница с функцией возвращающей HTML',
    'page callback' => 'mymodule_html_page',
    'access callback' => TRUE,
  );
 
  $items['mypage-ra'] = array(
    'title' => 'Страница возвращающая рендерный массив',
    'page callback' => 'mymodule_ra_page',
    'access callback' => TRUE,
  );
 
  return $items;
}
 
// Старый метод, который возвращает html код.
// Кстати, он ещё работает в седьмом Друпале. 
function mymodule_html_page {
  $output = '<p>A paragraph about some stuff...</p>';
  $output .= '<ul><li>first item</li><li>second item</li><li>third item</li></ul>';
  return $output;
}
 
// Новый метод, который возвращает рендерный массив
function mymodule_ra_page {
  $output =  array(
    'first_para' => array(
      '#type' => 'markup',
      '#markup' => '<p>A paragraph about some stuff...</p>',
    ),
    'second_para' => array(
      '#items' => array('first item', 'second item', 'third item'),
      '#theme' => 'item_list',
    ),
  );
  return $output;
}

Примеры массивов разных типов

Как и раньше, все элементы Drupal (см. hook_element_info(), который был hook_elements() в Drupal 6) представляют собой описанный тип данных. Глядя на system_element_info(), мы видим множество предопределенных типов, в том числе page, form, html_tag, value, markup, link, fieldset и многие другие. По соглашению, #- атрибуты, используемые этим типом, документируются с соответствующей функцией темизации. Таким образом, например, атрибуты, используемые в элементе типа #type => 'html_tag' можно найти в функции theme_html_tag().

Вот три примера из модуля Examples (Render example):

$demos = array(
  t('Super simple #markup')  => array(
    '#markup' => t('Some basic text in a #markup (shows basic markup and how it is rendered)'),
  ),
 
  'prefix_suffix' => array(
    '#markup' => t('This one adds a prefix and suffix, which put a div around the item'),
    '#prefix' => '<div><br/>(prefix)<br/>',
    '#suffix' => '<br/>(suffix)</div>',
  ),
 
  'theme for an element' => array(
    'child' => array(
      t('This is some text that should be put together'),
      t('This is some more text that we need'),
    ),
    '#separator' => ' | ',
    '#theme' => 'render_example_aggregate',
  ),
);

Примеры типов элементов

К рендерному массиву можно применить множество уже существующих типов или создать свои. Ниже приведены самые распространенные.

Обратите внимание, что многие из этих свойств описаны в Forms API, потому что в Forms API всегда использовались рендерное API для указания типов, но они не были задокументированы как типы рендерного API, коими они, несомненно, являются в Drupal 7.

#type Тип элемента. Если массив – элемент, то свойства элемента будут загружены по умолчанию. Это ведет к сокращению набора предопределенных свойств, которые могут быть взяты из описания этого элемента в hook_element_info().
#markup Простейшее свойство, которое просто создает строку с разметкой #type => 'markup'. По сути, с его помощью можно просто вставить кусок HTML’a без каких-либо преобразований или дальнейшего рендера.
#prefix/#suffix Используется при необходимости добавить строку (или разметку) в начале или в конце элемента.
#pre_render Массив функций, который может изменить рендерный массив перед вызовом рендера для него. Это свойство может изменить, удалить части, установить #printed = TRUE, чтобы предотвратить последующий рендер и т.д.
#post_render Массив функций, который может обрабатывать HTML, полученный в результате рендера элемента. По большому счету это тоже самое, что и #theme_wrappers, за исключением того, что не используется система темизации.
#theme Набор хуков темы, которые полностью ответственны за рендер элементов массива (включая дочерние).
Примечание: на самом деле, #theme в Drupal 7 и #theme в Drupal 6 не связаны между собой.
Обычно, #theme' => 'function_name' вызывает функцию вида theme_function_name(), а остальные значение массива передаются в эту функцию в качестве аргументов.
Вот список всех дефолтных хуков темы: http://api.drupal.org/api/drupal/modules--system--theme.api.php/group/themeable/7
#theme_wrappers Массив функций темы, который имеет возможность добавлять что-либо к рендерному массиву после того, как дочерние элементы были отрендерены и помещены в #children.
Обычно используется для добавления HTML вокруг отрендереных дочерних элементов, особенно если дочерние элементы были отрендерены рекурсивно с помощью собственных функций темизации. Это свойство редко используют вместе с #theme.
#cache Обозначает массив как кэшируемый и определяет срок его хранения. Если рендерный массив уже был отрендерен, он больше не будет рендироваться, пока не закончится срок хранения кэша. При кэшировании используются стандартные функции Друпала cache_get() и cache_set().

Этот атрибут может содержать такой массив массив:

  • 'keys' => массив ключей, которые будут объеденены для создания ключа кэша.
  • 'bin' => имя кэша, которое будет использоваться (Например, 'cache' или 'cache_page' и т.д.)
  • 'expire' => дата, записанная в Unix-формате, определяющая срок годности кэша.
  • 'granularity' => значение, обозначающая тип кэша. Например, DRUPAL_CACHE_PER_PAGE, DRUPAL_CACHE_PER_ROLE или DRUPAL_CACHE_PER_USER.

Обратите внимание, что элементы, помеченные с атрибутом #cache будут хранить кэш до тех пор, пока не запустится крон, не смотря на его срок годности.

Комментарии

Аватар пользователя Liqor
Liqor написал:

Спасибо!)) Очень полезно!

15.02.2012 15:19

Комментировать

                                                                        
88 88 ad888888b, 888888888888 ad888888b, 88888888ba
88 88 d8" "88 ,88 d8" "88 88 "8b
88 88 a8P ,88" a8P 88 ,8P
88 88 aad8" ,88" ,d8P" 88aaaaaa8P'
88 88 ""Y8, ,88" a8P" 88""""88'
88 88 "8b ,88" a8P' 88 `8b
Y8a. .a8P Y8, a88 88" d8" 88 `8b
`"Y8888Y"' "Y888888P' 888888888888 88888888888 88 `8b

Enter the code depicted in ASCII art style.