Сущности — отличный способ организовать ваши данные в Drupal. Если вы знакомы с узлами, терминами таксономии, комментариями или пользователями, вы также должны знать, что начиная с Drupal 7 это были сущности. Еще один важный аспект, касающийся их, заключается в том, что они доступны для использования через API Field.
В этом уроке я покажу вам, как вы можете определить свой собственный тип сущности и начать работать с ним. Зачем делать это вместо использования узлов? Потому что, хотя они и хороши, иногда узлы могут быть излишними. Существует множество функциональных возможностей, которые вам могут не понадобиться, такие как исправления или комментарии.
Для целей данного руководства мы определим наш собственный тип сущности, называемый project
для представления простой информации о наших проектах (заголовок, описание и крайний срок). Затем мы рассмотрим несколько вещей о работе с сущностями этого типа.
Для продолжения, я предполагаю, что вы знаете, как написать базовый пользовательский модуль (мой будет называться demo
). Вы можете найти отличный учебник по этой теме здесь . Идите вперед и напишите файл .info
и создайте пустые .module
и .install
. Я также настроил Git-репозиторий, в котором вы можете получить весь исходный код для этого урока (одна ветка на часть, две части будут опубликованы).
Кроме того, на вашем сайте должен быть включен модуль входа Entity API , который должен быть установлен как зависимость от вашего пользовательского модуля. Модуль Entity API очень эффективен при работе с сущностями, поскольку предоставляет множество функциональных возможностей, которых нет в ядре Drupal.
Определение нашего собственного типа сущности 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, 'Winter 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.', 1397501132);
Наконец, зарегистрируйте путь в Drupal (любой путь только для тестирования) с помощью hook_menu () и вставьте следующее в его функцию обратного вызова:
$projects = entity_load('project', array(1, 2)); dpm($projects); return 'Some string';
Сначала мы используем функцию entity_load () для загрузки сущностей проекта с идентификаторами 1 и 2, а затем печатаем их на экран с помощью функции dpm()
(поэтому убедитесь, что Devel включен на вашем сайте для тестирования). И не забывайте, что функция обратного вызова для страницы должна что-то возвращать, иначе она не будет построена.
Теперь, если вы перейдете на эту страницу, вы увидите в Krumo данные из двух сущностей в базе данных.
Кроме того, вы можете использовать класс EntityFieldQuery для запроса новых сущностей по любому желаемому свойству (а не только по id). Для получения дополнительной информации о том, как это работает, вы можете ознакомиться с данным руководством Sitepoint, которое поможет вам начать работу.
Класс сущности и контроллер
К сожалению, ядро Drupal не имеет слишком много вспомогательных функций для работы с сущностями ( entity_load()
является в значительной степени единственной). Однако модуль Entity API восполняет этот пробел.
Чтобы использовать его функциональность, нам нужно изменить информацию об объектах, которую мы объявили ранее, и указать классы PHP, которые можно использовать для работы с объектами. Сейчас мы добавим еще 2 ключа в project
ключами массива в нашем объявлении hook_entity_info()
:
... 'entity class' => 'Entity', 'controller class' => 'EntityAPIController', ...
Первый — это базовый класс, предоставляемый Entity API, который будет предлагать некоторые функции обёртывания для сущностей. Этот класс объявлен в файле entity.inc
модуля, и если вы загляните внутрь, вы заметите, что многие из его методов вызывают методы другого (контроллера) класса. Это класс, который мы указали для ключа controller class
.
Класс EntityAPIController
(находится в файле entity.controller.inc
модуля) предлагает некоторые разумные значения по умолчанию для работы с сущностями. Он расширяет стандартное ядро Drupal класса DrupalDefaultEntityController
и отвечает, среди прочего, за выполнение операций CRUD.
Оба эти класса могут быть расширены в вашем пользовательском модуле для настройки функций (таких как запросы, загрузка или отображение сущностей). Мы увидим, как это сделать через минуту.
Но сначала я хочу показать вам, как сохранить новую сущность. В настоящее время в моей базе данных есть 2 записи с идентификаторами 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';
Как видите, сейчас мы пытаемся загрузить 3 объекта проекта и проверить наличие третьего. Если он не существует, мы используем вспомогательную функцию entity_create()
предоставляемую API-интерфейсом Entity, устанавливаем для свойств некоторые случайные значения, а затем используем метод save()
для объекта, чтобы сохранить его в базе данных. Этот метод предоставляется классом Entity
и его задача — вызвать метод save()
для класса контроллера, который мы определили выше. И этот метод будет выполнять логику, необходимую для сохранения сущности. Но все это происходит за кулисами, и нам не нужно об этом беспокоиться.
Если вы перезагрузите эту страницу, вы должны увидеть только 2 возвращенных объекта проекта, но при загрузке во второй раз их должно быть 3.
Переопределение классов сущностей
Последнее, что я хочу показать вам в этой части руководства, — это как отображать ваши сущности. Для этого мы будем придерживаться функции обратного вызова страницы, с которой мы работали, и сделать так, чтобы она отображала список наших сущностей.
Первое, что нам нужно сделать, это переопределить метод buildContent()
класса EntityAPIController
по умолчанию. Причина в том, что контроллер не может делать предположения о наших данных, поэтому нам нужно предоставить некоторую информацию о том, как их отобразить. Во-первых, давайте объявим наш класс контроллера, который расширяет предыдущий:
/** * 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. Например, мы можем написать это прямо перед возвратом массива $build
:
$build['description'] = array( '#type' => 'markup', '#markup' => check_plain($entity->description), '#prefix' => '<div class="project-description">', '#suffix' => '</div>', ); $build['deadline'] = array( '#type' => 'markup', '#markup' => date('d F, Y', check_plain($entity->deadline)), '#prefix' => '<p>Deadline: ', '#suffix' => '</p>', );
Мы в основном добавляем два новых элемента в массив. Первый обернет описание <div class="project-description">
а второй выведет форматированную дату между тегами абзаца. Это базовая тема Drupal, так что попробуйте это, если вы не понимаете, что здесь происходит. Но вы заметите, что название проекта отсутствует. Это будет автоматически отображаться Drupal, потому что мы указали его в качестве label
в entity keys
hook_entity_info()
реализации hook_entity_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()
который мы только что переопределили. Эта функция возвращает список массивов рендеринга для каждого объекта. Мы визуализируем каждый из них и сохраняем результат в массиве $output
который затем взрываем и возвращаем.
Вы можете обновить страницу, и вы должны увидеть список всех объектов, которые вы загрузили. Убедитесь, что вы очистили кэши, чтобы изменения стали видимыми.
Вывод
В этом уроке мы начали изучать сущности в Drupal с определения нашего собственного типа сущности в коде. Мы видели, как написать определение схемы для данных, которые они представляют, и как зарегистрировать их в Drupal. Затем мы увидели мощь использования модуля вклада Entity API для объектно-ориентированного способа работы с сущностями.
Во второй части этого урока мы рассмотрим три основных аспекта. Сначала мы создадим несколько страниц для отображения отдельных сущностей проекта и добавим интерфейс администратора для управления проектами. Во-вторых, мы сделаем их доступными для использования через пользовательский интерфейс. И в-третьих, мы представим их в представлениях, чтобы мы могли выполнять некоторые правильные запросы и списки. Будьте на связи!