Сутності (entities) – відмінний спосіб організації даних в Drupal. Якщо ви знайомі з вузлами (node), термами в таксономії, коментарями чи користувачами в Drupal, ви вже повинні знати, що всі ці речі, починаючи з 7 версії Drupal, є сутностями.

Іншим важливим аспектом організації є те, що ці сутності можуть бути оснащені полями (fieldable) через програмний інтерфейс роботи з полями – Field API.

У цьому уроці я покажу, як можна визначити свій власний тип сутності і почати працювати з ним. Навіщо створювати свою сутність, якщо можна скористатися вузлами?

Тому що вузли, як би гарні вони не були, містять багато функціоналу, є надмірною для багатьох завдань. Наприклад, систему ревізій або можливість коментування.

В ході уроку ми створимо персональний тип сутності, який назвемо project, призначений для відображення інформації про проект: назва, опис і крайній термін виконання. Потім ми розглянемо деякі прийоми роботи з персональними сутностями.

Для розуміння матеріалу вам знадобляться основні навички побудови власних модулів. (Наш модуль буде називатися demo). Якщо ви готові, напишіть файл .info і створіть порожні файли .module і .install.

Я налаштував Git-репозиторій, звідки ви можете завантажити вихідні коди для нашого уроку. Наш урок буде складатися з двох частин; для кожної частини я створив по гілці в Git.

Також для роботи з прикладами вам потрібно встановити на вашому сайті додатковий модуль Entity API і встановити його як залежність в наш модуль. Entity API володіє потужними засобами для роботи з істотами, яких не вистачає ядра Drupal.

Визначення власного типу сутності

Щоб створити новий тип сутності, перш за все ми повинні оголосити його схему. Іншими словами, ми повинні написати код, який згенерує в базі даних таблицю для зберігання даних суті.

У моєму файлі demo.install міститься наступний код:

/**
* Implements hook_schema().
*/
function demo_schema() {
$schema = array();
$schema[‘demo_projects’] = array(
‘description’ => ‘The base table for the Project entity’,
‘fields’ => array(
‘id’ => array(
‘description’ => ‘Primary key of the Project entity’,
‘type’ => ‘serial’,
‘unsigned’ => TRUE,
‘not null’ => TRUE,
),
‘name’ => array(
‘description’ => ‘Project name.’,
‘type’ => ‘varchar’,
‘length’ => 255,
‘not null’ => FALSE,
),
‘description’ => array(
‘description’ => ‘Project description.’,
‘type’ => ‘text’,
‘size’ => ‘big’,
‘not null’ => FALSE,
‘default’ => NULL
),
‘deadline’ => array(
‘description’ => ‘Project deadline.’,
‘type’ => ‘int’,
‘length’ => 11,
‘not null’ => FALSE,
),
),
‘primary key’ => array(‘id’),
);
return $schema;
}

Це досить проста реалізація зворотного виклику hook_schema(), за допомогою якої ми створюємо таблицю demo_projects, яка має 4 стовпця: id, name, description і deadline, причому перше поле є ключем. Нічого особливого.

Наступним нашим кроком стане реалізація hook_entity_info(). У цьому процесорі можна задати багато різних опцій, але ми обмежимося основними, найбільш необхідними з них.

Ось відповідний код з файлу demo.module:

/**
* Implements hook_entity_info().
*/
function demo_entity_info() {
$info = array();
$info[‘project’] = array(
‘label’ => t(‘Project’),
‘base table’ => ‘demo_projects’,
‘entity keys’ => array(
‘id’ => ‘id’,
‘label’ => ‘name’,
),
‘module’ => ‘demo’,
);
return $info;
}

Поле масиву $info, повертається цим обробником, містить машинно-читаний ім’я сутності. У масиві визначені ще кілька опцій, і в ході уроку ми додамо ще більше.

Поки ми зупинимося на полях ‘label’ – людино-читається ім’я сутності, ‘base table’ – поле для зберігання даних суті, ‘entity keys’ – властивості сутності, службовці для ідентифікації, і ‘module’ – вказує на модуль, який визначає тип сутності. Останнє поле необов’язково, але його рекомендується вказати.

Таким чином, ми зареєстрували наш простий тип сутності в Drupal. Щоб перевірити свою роботу, активуйте цей модуль і переконайтеся, що таблиця в базі даних створено.

Потім заповніть таблицю кількома полями для майбутніх тестів:

INSERT INTO `demo_projects` (`id`, `name`, `description`, `deadline`)
VALUES
(1, ‘Summer House’, ‘Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.’, 1397501105),
(2, ‘House Winter’, ‘Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.’, 1397501132);

Нарешті, зареєструйте шлях в Drupal з використанням hook_menu() (для перевірки підійде будь-шлях) і створіть наступну функцію зворотного виклику:

$projects = entity_load(‘project’, array(1, 2));
dpm($projects);
return ‘Some string’;

Спочатку ми скористаємося entity_load(), щоб завантажити сутності типу project з номерами 1 і 2, потім ми виведемо їх на екран за допомогою функції dpm().

Щоб ця функція спрацювала, налагоджувальну інформацію (Devel) в Drupal повинен бути дозволений. І не забудьте, що callback сторінки повинен повернути якесь значення, інакше він не запуститься.

Тепер, якщо ви перейдете на сторінку, задану зареєстрованого раніше шляхом, ви побачите дані з таблиці нашого модуля в налагоджувальному висновку, сформованому Krumo.

В якості альтернативи ви можете скористатися класом EntityFieldQuery, щоб отримати будь-яку властивість сутності, а не лише ключ.

Клас і контролер сутності

На жаль, функції для роботи з сутностями в Drupal не відрізняються різноманітністю. Точніше кажучи, entity_load() є єдиною такою функцією. Однак модуль Entity API виправляє цей недолік.

Щоб скористатися Entity API, ми повинні змінити інформацію про тип сутності та задати класи, які будуть працювати з сутностями.

Поки що ми додамо 2 ключа в масив project, заданий обробником hook_entry_info():

‘entity class’ => ‘Entity’,
‘controller class’ => ‘EntityAPIController’,

Перший заданий нами клас міститься в Entity API і обертає деякі функції для виконання їх від особи сутності.

Цей клас оголошений у файлі entity.inc, і якщо ми заглянемо всередину цього файлу, то зауважимо, що багато його методи транслюють виклики методів іншого класу – класу controller, який ми вказали в ключі ‘controller class’.

Клас EntityAPIController, реалізований у файлі entity.controller.inc, пропонує деякі осмислені дії, вироблені над сутностями за замовчуванням.

Він розширює базовий клас Drupal DrupalDefaultEntityController і відповідає, крім іншого, за CRUD-операції (створення, редагування та видалення сутностей).

Обидва ці класу можуть бути розширені у вашому власному модулі, щоб уточнити функції начебто пошуку, завантаження або відображення сутності. Скоро ми дізнаємося, як це робиться.

Але спочатку я покажу вам, як зберегти нову сутність. Поки що в нашій таблиці є дві сутності з ідентифікаторами 1 і 2.

Я хочу дописати тестовий код відображення сторінки так, щоб він міг створити сутність з ідентифікатором 3, якщо її ще не існує. Це може виглядати так:

$projects = entity_load(‘project’, array(1, 2, 3));
if (!isset($projects[3])) {
$entity = entity_create(‘project’, array(‘id’ => 3));
$entity->name = t(‘Spring House’);
$entity->description = t(‘Some more lipsum.’);
$entity->save();
}
dpm($projects);
return ‘Some string’;

Як бачите, тепер ми завантажуємо 2 суті і перевіряємо існування третьої. Якщо її не існує, ми використовуємо допоміжну функцію Entity API entity_create(), встановлюємо властивості сутності і використовуємо метод сутності save(), щоб занести її в базу даних.

Цей метод надано класом Entity, і є обгорткою однойменного методу класу-контролера. Саме в контролері реалізована логіка збереження даних. Але ці деталі відбуваються за сценою, так що нам не потрібно про них турбуватися.

Якщо ви оновіть нашу сторінку, на ній як і раніше будуть дві сутності. Але перезавантажте сторінку ще раз, і сутностей стане 3.

Перевизначення класів сутностей

Останнє, що я хочу показати вам в цій частині нашого уроку це те, як відображати сутність власного типу. Для цього ми ще трохи попрацюємо над обробником відображення сторінки, змусивши його відображати список наших сутностей.

Але спочатку ми повинні перевизначити метод класу-контролера за замовчуванням buildContent(). Це необхідно зробити, тому що контролер не може нічого знати про те, як влаштовані наші дані, так що ми повинні надати йому деяку інформацію про те, як їх відображати.

Насамперед, оголосимо власний клас контролера, який розширить контролер за замовчуванням:

/**
* Extending the EntityAPIController for the Project entity.
*/
class ProjectEntityController extends EntityAPIController {
}

Я вибрав нашого класу ім’я ProjectEntityController. Тепер ми повинні замінити значення ключа ‘controller class’ в нашій реалізації hook_entity_info() на ім’я нового класу. Не забувайте про це дії.

В реалізації нашого класу ми запозичимо ім’я методу і повертається методом значення у оригінального класу:

public function buildContent($entity, $view_mode = ‘full’, $langcode = NULL, $content = array()) {
$build = parent::buildContent($entity, $view_mode, $langcode, $content);
// Our additions to the $build render array
return $build;
}

Поки ми не зробили нічого нового, але тепер ми можемо додати свої дані до повертається методом значенням, яке являє собою не що інше, як стандартний масив Drupal – render array.

Так що ми можемо написати наступний код безпосередньо перед поверненням $build:

$build[‘description’] = array(
‘#type’ => ‘мова’,
‘#markup’ => check_plain($entity->description),
‘#prefix’ =>’
‘,
‘#suffix’ =>’
‘,
);
$build[‘deadline’] = array(
‘#type’ => ‘мова’,
‘#markup’ => date(‘d F, Y’, check_plain($entity->deadline)),
‘#prefix’ => ‘

Deadline: ‘,
‘#suffix’ => ‘

‘,
);

Ми додали в метод дві речі. По-перше, виведення вмісту поля description обертається тегом
. А по-друге, ми виводимо форматовану дату в тезі параграфа.

Це відповідає оформлення дефолтної теми Drupal, так що, якщо нічого не розумієте в цій розмітці, залиште поки все як є. Але ви, напевно, помітили, що ми не використали поле з назвою проекту.

Воно буде виводитися Drupal автоматично, так як ми вказали його як label ‘entity keys’, в оброблювачі hook_entry_info().

Останнім кроком буде модифікація функції відображення сторінок, щоб вона показувала наші сутності. Ось простий і швидкий спосіб, відповідний для цілей демонстрації:

$projects = entity_load(‘project’, array(1, 2, 3));
$list = entity_view(‘project’, $projects);
$output = array();
foreach ($list[‘project’] as $project) {
$output[] = drupal_render($project);
}
return implode($output);

Як і раніше, ми спочатку завантажуємо наші сутності через їх ідентифікатори. Потім ми обробляємо їх функцією entity_view(), яка, зрештою, викликає перевантажений нами метод buildContent().

Ця функція повертає список масивів відображення (render array), по масиву на кожну сутність. Ми відображаємо кожну сутність і складаємо результат в масив $output, який розгортаємо перед виходом.

Обновіть сторінку, щоб помилуватися на результат — список сутностей, які ми створили. Якщо результат не такий, як очікується, перевірте на всякий випадок, що всі кеші очищені.

Висновок

У цьому уроці ми навчилися створювати сутності Drupal в коді. Ми зрозуміли, як написати схему для даних сутності та зареєструвати цю схему в Drupal. Ми застосували всю міць модуля Entity API до роботи з сутностями в об’єктно-орієнтованому стилі.

У другому уроці ми зробимо три важливі речі. По-перше, ми створимо сторінки для відображення окремих сутностей і для адміністрування проектів.

По-друге, ми оснастимо наші сутності настроюваними полями через інтерфейс Drupal. По-третє, ми забезпечимо доступ до наших сутностей через модуль Views, щоб здійснювати до них стандартні запити і включати їх у списки.

Залишайтеся з нами!

Переклад статті «Build Your Own Custom Entities in Drupal – Setup» був підготовлений дружною командою проекту Сайтостроение від А до Я.