{{< minver v="1.7.6" title="true" >}}
Введение
В этом учебном пособии мы создадим модуль, который расширяет список клиентов одной дополнительной колонкой, которую можно переключать. У нее может быть два состояния - включено или выключено. В форме создания и редактирования клиента мы добавим переключатель, который также будет управлять тем же состоянием. Следуя этому руководству, вы узнаете, как:
- расширять современные сетки. [Компонент Grid]({{< relref "/8/development/components/grid/" >}})
- расширять форму идентифицируемого объекта. [Форма идентифицируемого объекта]({{< relref "/8/development/architecture/migration-guide/forms/CRUD-forms" >}})
Модуль, созданный в рамках этого учебного пособия, можно найти здесь
Предварительные требования
- Знакомство с основами создания модулей.
Регистрация хуков
При установке модуля регистрируются следующие хуки:
action
CustomerGridDefinitionModifier
- для добавления новой колонки в сетку клиентов.action
CustomerGridQueryBuilderModifier
- для изменения SQL-запроса сетки клиентов.action
CustomerFormBuilderModifier
- для добавления нового поля в форму создания или редактирования клиентов.actionAfterCreate
CustomerFormHandler
- для выполнения процесса сохранения добавленного поля из модуля.actionAfterUpdate
CustomerFormHandler
- для выполнения процесса обновления добавленного поля из модуля.
<?php
public function install()
{
return parent::install() &&
$this->registerHook('actionCustomerGridDefinitionModifier') &&
$this->registerHook('actionCustomerGridQueryBuilderModifier') &&
$this->registerHook('actionCustomerFormBuilderModifier') &&
$this->registerHook('actionAfterCreateCustomerFormHandler') &&
$this->registerHook('actionAfterUpdateCustomerFormHandler') &&
$this->installTables()
;
}
{{% notice note %}}
Хуки action
CustomerGridDefinitionModifier
и action
CustomerGridQueryBuilderModifier
создаются
используя id сетки, который в данном случае Customer. Если вы хотите использовать хук для любой другой сетки,
Вы можете проверить любой сервис фабрики определения в PrestaShop\PrestaShop\Core\Grid\Definition\Factory
, чтобы увидеть доступные id сеток. Id сетки возвращается методом getId()
.
Хуки action
CustomerFormBuilderModifier
,actionAfterCreate
CustomerFormHandler
и actionAfterUpdate
CustomerFormHandler
создаются с использованием уникального идентификатора, который
в данном случае Customer, полученного из его типа формы CustomerType. Например, id, полученный из ManufacturerType, будет Manufacturer. Некоторые типы могут использовать
функцию getBlockPrefix
для получения уникального id
{{% /notice %}}
Добавление новой колонки в сетку клиентов
Расширение определения сетки и фильтров
<?php
use PrestaShop\PrestaShop\Core\Grid\Definition\GridDefinitionInterface;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ToggleColumn;
use PrestaShopBundle\Form\Admin\Type\YesAndNoChoiceType;
class Ps_DemoCQRSHooksUsage extends Module
{
// ...
/**
* Хук позволяет изменять определение сетки клиентов.
* Этот хук - правильное место для добавления/удаления колонок или действий (bulk, grid).
*
* @param array $params
*/
public function hookActionCustomerGridDefinitionModifier(array $params)
{
/** @var GridDefinitionInterface $definition */
$definition = $params['definition'];
$translator = $this->getTranslator();
$definition
->getColumns()
->addAfter(
'optin',
(new ToggleColumn('is_allowed_for_review'))
->setName($translator->trans('Разрешено для обзора', [], 'Modules.Ps_DemoCQRSHooksUsage'))
->setOptions([
'field' => 'is_allowed_for_review',
'primary_field' => 'id_customer',
'route' => 'ps_democqrshooksusage_toggle_is_allowed_for_review',
'route_param_name' => 'customerId',
])
)
;
$definition->getFilters()->add(
(new Filter('is_allowed_for_review', YesAndNoChoiceType::class))
->setAssociatedColumn('is_allowed_for_review')
);
}
// ...
}
Этот хук, через массив $params
, получает GridDefinition
, который определяет, как сетка отображается. Смотрите [Определение сетки]({{< relref "/8/development/components/grid/#grid-definition" >}}) для получения дополнительной информации.
В этом примере добавляется новая переключаемая колонка, которая определяет, может ли клиент оставлять обзоры продуктов, сразу после другой колонки с id optin
. Пример кода также демонстрирует, как добавить новый фильтр.
Создание маршрута для переключаемой колонки
ToggleColumn
- используется для отображения булевых значений, он будет отображать значок вместо значения. Если пользователь нажмет на него, это вызовет переключение булевого значения. Более подробную информацию об этой колонке и всех доступных параметрах можно найти [здесь]({{< relref "/8/development/components/grid/columns-reference/toggle" >}}).
В этом примерном модуле мы создаем ToggleColumn
, поэтому нам нужно настроить маршрут, в котором будет выполнено действие переключения. Действительно, когда конечный пользователь нажимает на эту колонку, выполняется ajax-запрос, который должен достигнуть нового контроллера для обработки действия (здесь: переключение значения вкл/выкл).
Если вы хотите только отображать данные, этот шаг можно пропустить. Например, вы создаете DataColumn
. Смотрите [Ссылки на колонки]({{< relref "/8/development/components/grid/columns-reference/" >}}) для полного списка доступных колонок сетки.
- Создайте контроллер
DemoCQRSHooksUsage\Controller\Admin\CustomerReviewController
:
<?php
namespace DemoCQRSHooksUsage\Controller\Admin;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
class CustomerReviewController extends FrameworkBundleAdminController
{
}
- Создайте действие контроллера
action
:
{{% notice note %}} Этот пример был упрощен по практическим причинам.
Вы можете найти полную реализацию здесь, которая использует шаблон CQRS для переключения состояния рецензента. [Подробнее об этом здесь]({{< relref "/8/development/architecture/domain/cqrs" >}}). {{% /notice %}}
<?php
namespace DemoCQRSHooksUsage\Controller\Admin;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
class CustomerReviewController extends FrameworkBundleAdminController
{
public function toggleIsAllowedForReviewAction($customerId)
{
// Обновление состояния рецензента можно обработать здесь
return $this->redirectToRoute('admin_customers_index');
}
}
- Так как это Symfony контроллер, мы должны настроить связанное маршрутизирование (читайте больше о маршрутизации symfony), что означает создание маршрута в файле
ps_democqrshooksusage/config/routes.yml
:
ps_democqrshooksusage_toggle_is_allowed_for_review:
path: demo-cqrs-hook-usage/{customerId}/toggle-is-allowed-for-review
methods: [POST]
defaults:
_controller: 'DemoCQRSHooksUsage\Controller\Admin\CustomerReviewController::toggleIsAllowedForReviewAction'
requirements:
customerId: \d+
Имя маршрута ps_democqrshooksusage_toggle_is_allowed_for_review
совпадает с тем, которое было передано как обязательный параметр при создании
ToggleColumn
.
Расширение построителя запросов сетки
Просто расширяя определение сетки, мы не сможем отображать какие-либо данные, поскольку нам нужно сначала их получить. К счастью, мы можем добавить дополнительные условия SQL путем расширения построителя запросов doctrine.
<?php
use Doctrine\DBAL\Query\QueryBuilder;
use PrestaShop\PrestaShop\Core\Search\Filters\CustomerFilters;
class Ps_DemoCQRSHooksUsage extends Module
{
// ...
/**
* Хук позволяет изменять построитель запросов клиентов и добавлять пользовательские SQL-выражения.
*
* @param array $params
*/
public function hookActionCustomerGridQueryBuilderModifier(array $params)
{
/** @var QueryBuilder $searchQueryBuilder */
$searchQueryBuilder = $params['search_query_builder'];
/** @var CustomerFilters $searchCriteria */
$searchCriteria = $params['search_criteria'];
$searchQueryBuilder->addSelect(
'IF(dcur.`is_allowed_for_review` IS NULL,0,dcur.`is_allowed_for_review`) AS `is_allowed_for_review`'
);
$searchQueryBuilder->leftJoin(
'c',
'`' . pSQL(_DB_PREFIX_) . 'democqrshooksusage_reviewer`',
'dcur',
'dcur.`id_customer` = c.`id_customer`'
);
if ('is_allowed_for_review' === $searchCriteria->getOrderBy()) {
$searchQueryBuilder->orderBy('dcur.`is_allowed_for_review`', $searchCriteria->getOrderWay());
}
foreach ($searchCriteria->getFilters() as $filterName => $filterValue) {
if ('is_allowed_for_review' === $filterName) {
$searchQueryBuilder->andWhere('dcur.`is_allowed_for_review` = :is_allowed_for_review');
$searchQueryBuilder->setParameter('is_allowed_for_review', $filterValue);
if (!$filterValue) {
$searchQueryBuilder->orWhere('dcur.`is_allowed_for_review` IS NULL');
}
}
}
}
// ...
}
Этот пример демонстрирует, как расширить SQL-запрос сетки клиентов. Из нашей пользовательской таблицы базы данных democqrshooksusage_reviewer
мы извлекаем результат поля is_allowed_for_review
. Это имя должно совпадать с id, который мы добавили в определение сетки. Для того чтобы сортировка работала, мы также добавляем условие orderBy
, и наконец, для того чтобы фильтры работали, добавляются условия where
, если фильтр существует в $searchCriteria->getFilters()
.
Результат
После выполнения вышеуказанных шагов при переходе к списку клиентов вы должны увидеть новую колонку "Разрешено для обзора".
{{< figure src="../img/extended_customers_grid.png" title="Добавлена колонка Разрешено для обзора в список клиентов" >}}
Добавление нового поля формы в форму клиента
Изменение построителя форм клиентов
На этом этапе мы добавляем в форму клиентов новое поле формы SwitchType
- это один из многих типов форм, которые уже существуют в PrestaShop. Более подробную информацию
об этом можно найти [здесь]({{< relref "/8/development/components/form/types-reference/" >}}).
{{% notice note %}} Этот пример был упрощен по практическим причинам.
Вы можете найти полную реализацию здесь, которая использует шаблон CQRS для получения состояния рецензента. [Подробнее об этом здесь]({{< relref "/8/development/architecture/domain/cqrs" >}}). {{% /notice %}}
<?php
// modules/ps_democqrshooksusage/ps_democqrshooksusage.php
use Symfony\Component\Form\FormBuilderInterface;
use PrestaShopBundle\Form\Admin\Type\SwitchType;
class Ps_DemoCQRSHooksUsage extends Module
{
// ...
public function hookActionCustomerFormBuilderModifier(array $params)
{
/** @var FormBuilderInterface $formBuilder */
$formBuilder = $params['form_builder'];
$formBuilder->add('is_allowed_for_review', SwitchType::class, [
'label' => $this->getTranslator()->trans('Разрешить отзывы', [], 'Modules.Ps_DemoCQRSHooksUsage'),
'required' => false,
]);
$customerId = $params['id'];
$params['data']['is_allowed_for_review'] = $this->getIsAllowedForReview($customerId);
$formBuilder->setData($params['data']);
}
private function getIsAllowedForReview($customerId)
{
// реализуйте свою логику извлечения данных здесь
return true;
}
// ...
}
В этом примере, используя построитель форм Symfony, мы просто добавили другой тип формы. Чтобы определить, включен он или выключен, нам также нужно сбросить его данные формы, присвоив значение is_allowed_for_review
true
или false
.
Результат
Выполнив вышеуказанные шаги, новый переключатель теперь виден в форме клиентов.
{{< figure src="../img/allow_for_review_switch.png" title="Переключатель Разрешено для обзора добавлен в форму клиентов" >}}
Расширение формы клиентов после создания и обновления действий
В предыдущем примере мы добавили поле переключателя! Но когда мы хотим сохранить его состояние (включено или выключено), ничего не происходит. Данные не изменяются. Это потому, что мы не использовали хуки, предназначенные для обработки этой темы - давайте сделаем это!
{{% notice note %}} Этот пример был упрощен по практическим причинам.
Вы можете найти полную реализацию здесь, которая использует паттерн CQRS для создания или обновления состояния рецензента. [Подробнее об этом здесь]({{< relref "/8/development/architecture/domain/cqrs" >}}). {{% /notice %}}
<?php
public function hookActionAfterUpdateCustomerFormHandler(array $params)
{
$this->updateCustomerReviewStatus($params);
}
public function hookActionAfterCreateCustomerFormHandler(array $params)
{
$this->updateCustomerReviewStatus($params);
}
private function updateCustomerReviewStatus(array $params)
{
$customerId = $params['id'];
/** @var array $customerFormData */
$customerFormData = $params['form_data'];
$isAllowedForReview = (bool) $customerFormData['is_allowed_for_review'];
// реализация сохранения статуса рецензии здесь
}
когда мы создавали форму типа переключателя, мы назвали её is_allowed_for_review
. Используя то же самое название, мы можем получить состояние (включено или выключено).
Этот хук получает от $params
данные формы, которые можно извлечь вот так: $params['form_data']
.
Все данные формы доступны здесь, включая данные is_allowed_for_review
, которые поступают от переключателя.