Запросы: Db и DbQuery
Таблица отзывов создана, теперь её нужно наполнять и читать. Запросы к базе выполняет класс Db, а запрос на выборку удобно собирать построителем DbQuery — он сам добавляет приставку таблиц и расставляет части запроса по местам.
Вставка строки
Добавьте в главный класс метод, который сохраняет отзыв:
// modules/acmehello/acmehello.php
public function addReview(int $productId, string $author, int $rating, string $content): bool
{
return Db::getInstance()->insert('acmehello_review', [
'id_product' => $productId,
'author' => pSQL($author),
'rating' => $rating,
'content' => pSQL($content),
'date_add' => date('Y-m-d H:i:s'),
]);
}Имя таблицы пишут без приставки — insert() добавит её сам. Функция pSQL() экранирует строку, чтобы кавычка в тексте не сломала запрос.
Чтобы было что читать, добавьте пару строк прямо в базу:
INSERT INTO ps_acmehello_review (id_product, author, rating, content, date_add)
VALUES (1, 'Anna', 5, 'Great product', NOW()), (1, 'Boris', 4, 'Good', NOW());Чтение
// modules/acmehello/acmehello.php
public function getReviews(int $productId): array
{
$query = new DbQuery();
$query->select('r.id_review, r.author, r.rating, r.content, r.date_add')
->from('acmehello_review', 'r')
->where('r.id_product = ' . $productId)
->orderBy('r.date_add DESC')
->limit((int) Configuration::get('ACMEHELLO_LIMIT'));
return Db::getInstance()->executeS($query) ?: [];
}from() принимает имя таблицы без приставки и короткий псевдоним. executeS() возвращает массив строк, каждая строка — массив «колонка — значение».
Использование в хуке
Замените в обработчике хука массив-заглушку на вызов метода:
// modules/acmehello/acmehello.php
public function hookDisplayFooterProduct(array $params): string
{
$this->context->smarty->assign([
'reviews' => $this->getReviews((int) Tools::getValue('id_product')),
]);
return $this->fetch('module:acmehello/views/templates/hook/product-reviews.tpl');
}Откройте на витрине товар с номером 1: в блоке отзывов теперь строки из базы. У остальных товаров — «Отзывов пока нет».
Методы чтения
| Метод | Что возвращает |
|---|---|
executeS($query) | Все строки |
getRow($query) | Первую строку |
getValue($query) | Первое значение первой строки |
execute($sql) | true или false — для запросов без результата |
Средняя оценка товара — одно значение, для него подходит getValue():
$query = new DbQuery();
$query->select('AVG(r.rating)')
->from('acmehello_review', 'r')
->where('r.id_product = ' . (int) $productId);
$average = round((float) Db::getInstance()->getValue($query), 1);Методы DbQuery
| Метод | Часть запроса |
|---|---|
select('a.id, a.name') | Колонки |
from('table', 'a') | Таблица и псевдоним |
leftJoin('product', 'p', 'p.id_product = a.id_product') | Соединение |
where('a.active = 1') | Условие; несколько вызовов соединяются через AND |
groupBy('a.id_product') | Группировка |
orderBy('a.date_add DESC') | Сортировка |
limit(10, 20) | Количество и смещение |
Обновление и удаление
$db = Db::getInstance();
$db->update('acmehello_review', ['rating' => 4], 'id_review = ' . (int) $reviewId);
$db->delete('acmehello_review', 'id_review = ' . (int) $reviewId);
$newId = (int) $db->Insert_ID();Третий аргумент update() и второй аргумент delete() — условие WHERE. Insert_ID() возвращает номер последней вставленной строки.
Частая ошибка
Значение из запроса, вставленное в условие напрямую, — это SQL-инъекция: ->where('id_product = ' . Tools::getValue('id_product')). Класс Db не подставляет параметры за вас. Каждое число приводите через (int), каждую строку пропускайте через pSQL() и берите в кавычки: "author = '" . pSQL($author) . "'".