Encodera

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

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

Оглавление

Запросы к базе данных

Запросы в Joomla не пишут строкой SQL. Их собирают построителем — объектом с методами select(), from(), where(). Он подставляет приставку таблиц, экранирует имена и защищает от SQL-инъекций. В моделях прошлого урока построитель уже использовался; разберём его по частям.

Где взять объект базы

Где находится кодКак получить
Модель компонента$db = $this->getDatabase();
Помощник модуля с DatabaseAwareTrait$db = $this->getDatabase();
Любое другое место$db = Factory::getContainer()->get(DatabaseInterface::class);

Для третьего способа нужны строки use Joomla\CMS\Factory; и use Joomla\Database\DatabaseInterface;.

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

// components/com_hello/src/Model/PostsModel.php, внутри метода модели
$db = $this->getDatabase();
 
$query = $db->getQuery(true)
    ->select($db->quoteName(['id', 'title']))
    ->from($db->quoteName('#__hello_posts'));
 
$posts = $db->setQuery($query)->loadObjectList();

getQuery(true) создаёт новый пустой запрос. quoteName() берёт имена столбцов и таблиц в кавычки. setQuery() передаёт запрос базе, а loadObjectList() выполняет его и возвращает массив объектов: $posts[0]->title.

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

$query = $db->getQuery(true)
    ->select($db->quoteName(['id', 'title', 'created']))
    ->from($db->quoteName('#__hello_posts'))
    ->where($db->quoteName('published') . ' = 1')
    ->order($db->quoteName('created') . ' DESC')
    ->setLimit(10);

Несколько вызовов where() соединяются через AND. setLimit(10) оставляет десять строк; второй аргумент — сколько строк пропустить.

Значения от пользователя

Всё, что пришло извне, не вклеивают в запрос, а привязывают параметром. Добавим в модель списка поиск по заголовку:

// components/com_hello/src/Model/PostsModel.php
use Joomla\CMS\Factory;
use Joomla\Database\ParameterType;
 
protected function getListQuery(): QueryInterface
{
    $db = $this->getDatabase();
 
    $query = $db->getQuery(true)
        ->select($db->quoteName(['id', 'title', 'created']))
        ->from($db->quoteName('#__hello_posts'))
        ->where($db->quoteName('published') . ' = 1')
        ->order($db->quoteName('created') . ' DESC');
 
    $search = Factory::getApplication()->getInput()->getString('q', '');
 
    if ($search !== '') {
        $search = '%' . $search . '%';
 
        $query->where($db->quoteName('title') . ' LIKE :search')
            ->bind(':search', $search);
    }
 
    return $query;
}

В запросе стоит метка :search, а значение передаётся отдельно методом bind(). Откройте index.php?option=com_hello&view=posts&q=первая — в списке осталась одна запись. Для чисел указывают тип: ->bind(':id', $id, ParameterType::INTEGER).

Чтение результата

МетодЧто возвращает
loadObjectList()Все строки — массив объектов
loadAssocList()Все строки — массив массивов
loadObject()Одну строку объектом или null
loadResult()Одно значение — первый столбец первой строки
loadColumn()Один столбец массивом

Например, число опубликованных записей:

$query = $db->getQuery(true)
    ->select('COUNT(*)')
    ->from($db->quoteName('#__hello_posts'))
    ->where($db->quoteName('published') . ' = 1');
 
$total = (int) $db->setQuery($query)->loadResult();

Вставка и изменение

$post = (object) [
    'title' => 'Новая запись',
    'body' => 'Текст записи',
];
 
$db->insertObject('#__hello_posts', $post, 'id');
 
$post->title = 'Исправленный заголовок';
$db->updateObject('#__hello_posts', $post, 'id');

Свойства объекта — столбцы таблицы. Третий аргумент — столбец первичного ключа: после вставки в $post->id окажется номер новой строки, а updateObject() по нему находит строку для изменения.

Удаление

$id = 5;
 
$query = $db->getQuery(true)
    ->delete($db->quoteName('#__hello_posts'))
    ->where($db->quoteName('id') . ' = :id')
    ->bind(':id', $id, ParameterType::INTEGER);
 
$db->setQuery($query)->execute();

Запросы, которые ничего не возвращают, выполняют методом execute(). В bind() передают переменную, а не выражение: метод принимает значение по ссылке.

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

Значение вклеивают в текст запроса: ->where('title = "' . $title . '"'). Кавычка в $title ломает запрос, а подобранная строка позволяет прочитать или стереть чужие данные — это SQL-инъекция. Всегда используйте bind(). И не пишите настоящую приставку вроде abc12_: на другом сайте она другая — только #__.

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

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