Entity API в Drupal: загрузка, создание и сохранение сущностей
В Drupal Entity API даёт единый способ работать с материалами, пользователями и другими сущностями. Разбираем, когда загружать запись по ID, когда создавать новую и почему прямой запрос к базе может обойти важную логику системы.

В Drupal 10 и 11 материал — не просто строка в таблице базы данных: его поля, переводы и сохранение проходят через Entity API. Если обращаться к базе напрямую, можно прочитать не те данные или обойти обработчики сохранения. Ниже — рабочие способы загрузить, создать, изменить и сохранить сущность, а также критерии выбора между ними.
Что считать сущностью
Сущность — объект Drupal с определённым типом и набором полей. Узел материала, пользователь, термин таксономии и файл — примеры контентных сущностей. У сущности обычно есть идентификатор, а система знает, как её загрузить и сохранить.
Тип сущности отвечает на вопрос «что это за объект», а пакет — на вопрос «какая разновидность контента». Например, node — тип сущности, а article — пакет узлов. Это разные значения: при создании материала они нужны оба.
Словарь: хранилище сущностей — сервис, который загружает и сохраняет сущности соответствующего типа. Обычно его получают через менеджер типов сущностей, а не создают вручную.
Если задача касается содержимого Drupal, сначала ищите решение через Entity API. Прямой SQL оставляйте для случаев, когда вы точно понимаете, какие гарантии системы при этом обходите.
Три способа получить сущность
В примерах используется Drupal 10 и 11. Для кода модуля передавайте менеджер типов сущностей через внедрение зависимостей; пример ниже показывает сами операции и предполагает, что переменная $entityTypeManager уже получена как сервис entity_type.manager.
Загрузить по идентификатору
Когда известен ID конкретной записи, используйте хранилище её типа. Метод загрузки возвращает сущность либо NULL, если записи нет.
$storage = $entityTypeManager->getStorage('node');
$node = $storage->load(42);
if ($node !== NULL) {
$title = $node->label();
}
Тип node здесь задан явно: хранилище пользователя или термина загружает другой тип объектов. Проверка на отсутствие обязательна, если ID пришёл из URL, формы или внешнего источника.
Найти несколько сущностей
Для выборки по условиям используйте запрос сущностей. Он возвращает идентификаторы; сами объекты можно загрузить отдельным вызовом.
$storage = $entityTypeManager->getStorage('node');
$ids = $storage->getQuery()
->condition('type', 'article')
->condition('status', 1)
->accessCheck(TRUE)
->execute();
$nodes = $storage->loadMultiple($ids);
Условие accessCheck(TRUE) просит запрос учитывать доступ текущего пользователя. Не заменяйте его на FALSE только ради того, чтобы получить больше результатов: сначала разберитесь, кто увидит их на странице и почему ограничение доступа можно обойти. Синтаксис запроса и проверки доступа смотрите в документации своей версии Drupal.
Создать и сохранить
Создание проходит через хранилище. Для узла укажите пакет и заголовок; дополнительные обязательные поля зависят от настроек сайта и конкретного типа материала.
$storage = $entityTypeManager->getStorage('node');
$node = $storage->create([
'type' => 'article',
'title' => 'Материал из модуля',
]);
$node->save();
$newId = $node->id();
Сохранение может завершиться исключением, если не заполнено обязательное поле или данные не проходят проверку. В прикладном коде обработайте ожидаемые ошибки и не сообщайте пользователю, что запись создана, пока сохранение не завершилось успешно.
Какой подход выбрать
| Задача | Подход | Что получаете | Цена и ограничение |
|---|---|---|---|
| Известен один ID | load() | Одну сущность или отсутствие записи | Не подходит для выборки по условиям |
| Нужен набор по условиям | getQuery(), затем loadMultiple() | Фильтрацию через API Drupal и объекты выбранных сущностей | При большом результате может потребоваться разбивка на порции |
| Нужно добавить запись | create(), заполнение полей, save() | Сущность с логикой сохранения Drupal | Нужно учитывать обязательные поля, права и обработчики |
| Нужно изменить запись | Загрузить, изменить поле, сохранить | Обновление существующей сущности | Сначала проверьте, что запись найдена и изменение разрешено |
Для изменения узла используйте тот же путь: загрузите его, измените нужное поле и сохраните. Например, заголовок можно задать через setTitle(). Перед записью проверьте права пользователя и то, что загружена именно ожидаемая сущность. Для списков старайтесь не загружать все записи сайта одним вызовом: выбирайте только нужные ID и обрабатывайте большие наборы порциями.
Что ломается и где подход не подходит
- Запрос возвращает пустой результат. Проверьте машинное имя пакета, условия и доступ текущего пользователя. Пустой массив не обязательно означает, что записи нет в базе.
- Сущность не сохраняется. Проверьте обязательные поля пакета и ошибки валидации. Требования могут отличаться между сайтами из-за конфигурации.
- Код загружает слишком много объектов. Ограничьте выборку и обрабатывайте ID порциями. Особенно опасно загружать весь каталог в память во время фоновой задачи.
- Изменение видно не сразу. Учитывайте кеширование Drupal и способ отображения сущности. Если проблема повторяется, выясните, какой кеш отвечает за конкретный вывод, вместо того чтобы без разбора очищать все кеши.
- Выборка раскрывает закрытые записи. Проверьте access check запроса и последующую проверку доступа перед выводом. Получить ID сущности и иметь право показать её — не одно и то же.
Entity API не заменяет работу с файлами, конфигурацией и произвольными таблицами. Для таких данных выбирают соответствующий API Drupal; не стоит маскировать их под сущности узлов только ради одинакового способа доступа.
Что проверить после внедрения
Начните с одного сценария: загрузки или создания одной сущности. Проверьте случай, когда ID отсутствует, и случай, когда пользователь не имеет права просматривать или изменять запись. Затем протестируйте выборку на объёме, близком к рабочему, и измерьте время выполнения и потребление памяти. Если записей много, добавьте порционную обработку; если результат неожиданен, сверяйте условия запроса и настройки доступа.
Следующий шаг — посмотреть документацию интерфейсов Entity API для той версии Drupal, на которой работает сайт, и отдельно проверить правила доступа для своего типа сущности. Индексация, миграции и работа с переводами — смежные темы; здесь мы разобрали базовый цикл чтения и записи.
Транскрибатор встреч: Запись созвона или диктофона — в текст с разделением по спикерам, протоколом и списком задач.
Спросить за 25 ₽Источники: Drupal API: EntityTypeManagerInterface, Drupal API: EntityStorageInterface
Частые вопросы
Можно ли загружать сущность прямо через SQL?
Чем тип сущности отличается от пакета?
Что вернёт load(), если записи с таким ID нет?
Почему запрос сущностей не находит опубликованный материал?
Можно ли использовать эти примеры без изменений в Drupal 9?
Как обрабатывать большой список сущностей?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.