Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Запросы к сущностям

Запрос к сущностям (entity query) ищет материалы по условиям: тип, статус, значение поля. Он возвращает только номера найденных сущностей, а сами сущности затем загружает хранилище. С его помощью страница /blog наконец покажет настоящие статьи.

Простой запрос

Запрос создаёт хранилище из прошлого урока:

// web/modules/custom/blog/src/Controller/BlogController.php
$storage = $this->entityTypeManager()->getStorage('node');
 
$ids = $storage->getQuery()
    ->accessCheck(TRUE)
    ->condition('type', 'article')
    ->execute();
 
$nodes = $storage->loadMultiple($ids);

condition('type', 'article') оставляет только статьи, execute() выполняет запрос и возвращает массив номеров. Вызов accessCheck() обязателен: TRUE означает «только то, что разрешено видеть текущему пользователю».

Условия, сортировка, ограничение

// web/modules/custom/blog/src/Controller/BlogController.php
$ids = $storage->getQuery()
    ->accessCheck(TRUE)
    ->condition('type', 'article')
    ->condition('status', 1)
    ->condition('created', strtotime('-30 days'), '>=')
    ->sort('created', 'DESC')
    ->range(0, 10)
    ->execute();

Запрос вернёт не больше десяти опубликованных статей за последние 30 дней, сначала новые. Третий аргумент condition() — оператор сравнения; без него проверяется равенство. range(0, 10) — смещение и количество.

ЗаписьЧто означает
condition('status', 1)Равно
condition('created', $time, '>=')Сравнение: >, >=, <, <=, <>
condition('title', '%drupal%', 'LIKE')Содержит подстроку
condition('type', ['article', 'page'], 'IN')Одно из значений
condition('field_tags.entity.name', 'PHP')По полю связанной сущности
exists('field_image')Поле заполнено
count()Вернуть количество вместо номеров

Список статей на странице

Соберём всё в методе list():

// web/modules/custom/blog/src/Controller/BlogController.php
public function list(): array
{
    $storage = $this->entityTypeManager()->getStorage('node');
 
    $ids = $storage->getQuery()
        ->accessCheck(TRUE)
        ->condition('type', 'article')
        ->condition('status', 1)
        ->sort('created', 'DESC')
        ->range(0, $this->config('blog.settings')->get('items_per_page'))
        ->execute();
 
    $nodes = $storage->loadMultiple($ids);
 
    return $this->entityTypeManager()
        ->getViewBuilder('node')
        ->viewMultiple($nodes, 'teaser');
}

Построитель вывода getViewBuilder('node') превращает материалы в массив вывода. Второй аргумент — режим отображения: teaser — краткий вид, full — полный. Страница /blog покажет свежие статьи так, как настроено на вкладке «Управление отображением» типа материала, и шаблоном node--article.html.twig из темы.

Создание

// в любом месте, например в команде Drush
$node = \Drupal::entityTypeManager()->getStorage('node')->create([
    'type' => 'article',
    'title' => 'Новая статья',
    'body' => ['value' => 'Текст статьи.', 'format' => 'basic_html'],
    'uid' => 1,
    'status' => 1,
]);
 
$node->save();

create() только создаёт объект, в базу его записывает save(). Обязательны type и title; uid — номер автора, status — опубликован ли материал. После сохранения $node->id() вернёт присвоенный номер.

Удаление

// в любом месте, например в команде Drush
$node->delete();
 
$storage->delete($storage->loadMultiple($ids));

Первая строка удаляет один материал, вторая — сразу несколько. Удаление необратимо.

Частая ошибка

Запрос без accessCheck() завершается исключением: Drupal требует явно решить, учитывать ли права. accessCheck(TRUE) нужен для всего, что выводится посетителю. FALSE допустимо только в служебных задачах — cron, команды Drush, обновления, — где пользователя нет. Перепутав, легко показать гостю неопубликованные материалы.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.