Расширение таблиц и форм панели
Страницы панели на Symfony собраны из двух кирпичей: таблица со списком (grid) и форма. Модуль может дополнить чужую таблицу или форму — добавить колонку в список покупателей, поле в форму покупателя. Для этого у каждой таблицы и формы есть набор хуков действия, имена которых строятся по шаблону.
Хуки таблицы
| Хук | Что позволяет изменить |
|---|---|
action<Имя>GridDefinitionModifier | Набор колонок, фильтров и действий |
action<Имя>GridQueryBuilderModifier | Запрос SQL, которым выбираются строки |
action<Имя>GridDataModifier | Уже выбранные строки |
<Имя> — идентификатор таблицы: Customer, Order, Category, Address. Для списка покупателей хуки называются actionCustomerGridDefinitionModifier и actionCustomerGridQueryBuilderModifier.
Колонка в списке покупателей
Добавим в список покупателей колонку «Отзывов». Сначала описание колонки:
// modules/acmehello/acmehello.php
use PrestaShop\PrestaShop\Core\Grid\Column\Type\DataColumn;
public function hookActionCustomerGridDefinitionModifier(array $params): void
{
$column = new DataColumn('reviews_count');
$column->setName($this->trans('Отзывов', [], 'Modules.Acmehello.Admin'));
$column->setOptions(['field' => 'reviews_count']);
$params['definition']->getColumns()->addAfter('email', $column);
}Строку use ставят в начало файла, до объявления класса. В $params['definition'] приходит описание таблицы. addAfter('email', ...) вставляет колонку после колонки с почтой, а опция field говорит, из какого поля строки брать значение.
Значение для колонки
Поля reviews_count в запросе пока нет. Его добавляет второй хук:
// modules/acmehello/acmehello.php
public function hookActionCustomerGridQueryBuilderModifier(array $params): void
{
$params['search_query_builder']->addSelect(
'(SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'acmehello_review` r
WHERE r.id_customer = c.id_customer) AS reviews_count'
);
}search_query_builder — построитель запроса Doctrine, которым таблица выбирает покупателей; таблица покупателей в нём имеет псевдоним c. Подзапрос считает отзывы каждого покупателя по колонке id_customer, добавленной в уроке о таблицах.
Как увидеть результат
Зарегистрируйте оба хука в install() и сбросьте модуль:
&& $this->registerHook('actionCustomerGridDefinitionModifier')
&& $this->registerHook('actionCustomerGridQueryBuilderModifier')php bin/console prestashop:module reset acmehelloОткройте «Клиенты → Клиенты»: после колонки с почтой появилась колонка «Отзывов» с числом у каждого покупателя.
Хуки формы
| Хук | Когда срабатывает |
|---|---|
action<Имя>FormBuilderModifier | Форма строится — можно добавить поле |
actionAfterCreate<Имя>FormHandler | Новая запись сохранена |
actionAfterUpdate<Имя>FormHandler | Существующая запись сохранена |
Поле в форме покупателя
// modules/acmehello/acmehello.php
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
public function hookActionCustomerFormBuilderModifier(array $params): void
{
$params['form_builder']->add('acme_trusted', CheckboxType::class, [
'label' => $this->trans('Проверенный автор отзывов', [], 'Modules.Acmehello.Admin'),
'required' => false,
]);
$params['data']['acme_trusted'] = (bool) Configuration::get('ACMEHELLO_TRUSTED_' . (int) $params['id']);
$params['form_builder']->setData($params['data']);
}form_builder — построитель формы Symfony. Метод add() добавляет флажок, а setData() подставляет его текущее значение. В $params['id'] лежит номер покупателя; при создании нового покупателя он пуст.
Сохранение поля
// modules/acmehello/acmehello.php
public function hookActionAfterUpdateCustomerFormHandler(array $params): void
{
Configuration::updateValue(
'ACMEHELLO_TRUSTED_' . (int) $params['id'],
(int) !empty($params['form_data']['acme_trusted'])
);
}В form_data приходят значения всех полей формы, включая добавленное. Здесь флажок для простоты хранится в Configuration; в настоящем модуле для этого заводят колонку в своей таблице. После регистрации трёх хуков и сброса модуля в форме покупателя появится флажок, и его состояние будет сохраняться.
Частая ошибка
Колонку добавили в описание таблицы, а запрос не изменили. Страница списка падает с ошибкой о неизвестном поле или показывает пустую колонку. Хуки GridDefinitionModifier и GridQueryBuilderModifier почти всегда идут парой: первый объявляет колонку, второй даёт для неё данные.