Модель ObjectModel
Писать insert() и update() для каждой таблицы вручную утомительно, и легко забыть про проверку значений. ObjectModel — базовый класс ядра, который представляет одну строку таблицы объектом: поля становятся свойствами, а сохранение, проверку и защиту значений класс берёт на себя. Так же устроены товары, заказы и покупатели в самом ядре.
Где лежит класс
Модели модуля хранят в папке classes. Создайте файл вручную:
modules/acmehello/
├── acmehello.php
├── classes/
│ └── AcmeReview.php
├── upgrade/
└── views/Описание модели
<?php
// modules/acmehello/classes/AcmeReview.php
class AcmeReview extends ObjectModel
{
public $id_product;
public $id_customer;
public $author;
public $rating = 5;
public $content;
public $date_add;
public static $definition = [
'table' => 'acmehello_review',
'primary' => 'id_review',
'fields' => [
'id_product' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true],
'id_customer' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId'],
'author' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 100],
'rating' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'],
'content' => ['type' => self::TYPE_STRING, 'validate' => 'isMessage'],
'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'],
],
];
}Публичные свойства повторяют колонки таблицы. Массив $definition называет таблицу без приставки, первичный ключ и поля. Имя класса начинается с приставки модуля, чтобы не совпасть с классом ядра.
Подключение
Движок не знает о файле, пока его не подключат. Добавьте строку в начало главного файла, после проверки _PS_VERSION_:
// modules/acmehello/acmehello.php
require_once __DIR__ . '/classes/AcmeReview.php';Теперь класс AcmeReview доступен везде, где загружен модуль.
Ключи описания поля
| Ключ | Что задаёт |
|---|---|
type | Тип: TYPE_INT, TYPE_BOOL, TYPE_STRING, TYPE_FLOAT, TYPE_DATE, TYPE_HTML |
validate | Имя метода класса Validate для проверки |
required | Поле обязательно |
size | Наибольшая длина строки |
Создание записи
Перепишите метод addReview() главного класса на модель:
// modules/acmehello/acmehello.php
public function addReview(int $productId, string $author, int $rating, string $content): bool
{
$review = new AcmeReview();
$review->id_product = $productId;
$review->id_customer = (int) $this->context->customer->id;
$review->author = $author;
$review->rating = $rating;
$review->content = $content;
return $review->add();
}add() проверяет поля по $definition, экранирует значения и выполняет вставку. Поле date_add заполняется текущим временем само. После вставки номер новой строки лежит в $review->id.
Загрузка, изменение, удаление
$review = new AcmeReview(7);
if (Validate::isLoadedObject($review)) {
$review->rating = 4;
$review->update();
}
$review->delete();Номер в конструкторе загружает строку из базы. Если строки с таким номером нет, объект создаётся пустым — поэтому результат проверяют через Validate::isLoadedObject().
| Метод | Что делает |
|---|---|
add() | Вставляет новую строку |
update() | Сохраняет изменения |
save() | Сам выбирает add() или update() |
delete() | Удаляет строку |
validateFields(false) | Проверяет поля, возвращает true или false |
Ошибки проверки
Если значение не проходит проверку, add() и update() бросают исключение PrestaShopException. Данные от пользователя проверяют заранее:
if (!$review->validateFields(false)) {
return false;
}С аргументом false метод не бросает исключение, а возвращает результат.
Списки по-прежнему через DbQuery
Модель работает с одной строкой. Список отзывов товара всё так же получают методом getReviews() из прошлого урока — запросом DbQuery.
Частая ошибка
В $definition добавили поле, а публичное свойство с тем же именем в классе не объявили, или наоборот. Значение молча не сохраняется или не загружается. Каждая колонка должна быть в трёх местах: в таблице, в свойствах класса и в fields.