Если модулю PrestaShop требуется собственная административная страница, разработчик сталкивается с двумя подходами: классическими ModuleAdminController и современными Symfony-контроллерами.
В PrestaShop 9 для новой разработки Back Office имеет смысл ориентироваться именно на Symfony. Такие страницы получают доступ к Twig, Dependency Injection, маршрутизации, современным сервисам PrestaShop и другим компонентам Symfony.
Разберём минимальную структуру такой страницы и несколько важных отличий от старого подхода.
Где находится современный контроллер
Legacy-контроллеры модулей обычно располагаются здесь:
controllers/admin/
Symfony-контроллеры размещаются в:
src/Controller/
Например:
mymodule/
├── config/
│ ├── routes.yml
│ └── services.yml
├── src/
│ └── Controller/
│ └── ImportController.php
├── views/
│ └── templates/
│ └── admin/
│ └── import.html.twig
└── mymodule.php
Именно src/Controller рекомендуется для современных Symfony-контроллеров модулей.
Какой базовый Controller использовать в PrestaShop 9
В старых примерах PrestaShop часто встречается:
FrameworkBundleAdminController
Для нового кода PrestaShop 9 рекомендует:
PrestaShopAdminController
Простейший контроллер может выглядеть так:
<?php
namespace Ewonta\MyModule\Controller;
use PrestaShopBundle\Controller\Admin\PrestaShopAdminController;
use Symfony\Component\HttpFoundation\Response;
final class ImportController extends PrestaShopAdminController
{
public function indexAction(): Response
{
return $this->render(
'@Modules/mymodule/views/templates/admin/import.html.twig'
);
}
}
FrameworkBundleAdminController сохраняется для совместимости, но официально считается устаревшим. Для новых модулей лучше сразу использовать PrestaShopAdminController.
Добавляем маршрут
Одного класса контроллера недостаточно. Symfony должен понимать, по какому URL его вызывать.
Создадим:
config/routes.yml
и добавим маршрут:
mymodule_import:
path: mymodule/import
methods: [GET]
defaults:
_controller: 'Ewonta\MyModule\Controller\ImportController::indexAction'
Маршруты модулей по умолчанию получают префикс /modules, поэтому административный адрес будет построен через систему маршрутизации PrestaShop.
Не стоит вручную формировать URL административной страницы строками. Symfony Router корректно сформирует адрес и необходимые параметры.
Контроллер в PrestaShop 9 является сервисом
Это одно из наиболее важных отличий PrestaShop 9.
Современный контроллер должен быть зарегистрирован как Symfony-сервис.
Например, в services.yml:
services:
_defaults:
autowire: true
autoconfigure: true
Ewonta\MyModule\Controller\ImportController: ~
Можно зарегистрировать сразу пространство имён модуля, если его архитектура это предусматривает.
Почему это важно?
Потому что теперь контроллер может получать зависимости непосредственно через Dependency Injection:
final class ImportController extends PrestaShopAdminController
{
public function __construct(
private readonly ProductImporter $productImporter
) {
}
public function indexAction(): Response
{
$this->productImporter->run();
return $this->render(
'@Modules/mymodule/views/templates/admin/import.html.twig'
);
}
}
В PrestaShop 9 контроллеры работают как сервисы, а привычный для старого Symfony-кода подход $this->get('service_name') больше не является основой современной архитектуры.
Не помещайте бизнес-логику в Controller
Технически ничто не мешает написать:
public function importAction(): Response
{
// открыть XML
// проверить товары
// обновить цены
// скачать изображения
// изменить остатки
// записать журнал
}
Но тогда через некоторое время Controller превращается в класс на несколько тысяч строк.
Лучше оставить ему только управление запросом:
HTTP Request
↓
Controller
↓
ProductImporter
↓
Repository / API / Services
↓
Response
Controller должен принять запрос, вызвать необходимую операцию и сформировать ответ.
Это хорошо сочетается с Dependency Injection и CQRS, о которых уже рассказывалось в предыдущих статьях >
Используем Twig вместо HTML внутри PHP
Для современных страниц Back Office представление лучше вынести в Twig:
{% extends '@PrestaShop/Admin/layout.html.twig' %}
{% block content %}
<div class="card">
<div class="card-header">
Импорт товаров
</div>
<div class="card-body">
...
</div>
</div>
{% endblock %}
Контроллер при этом только передаёт данные:
return $this->render(
'@Modules/mymodule/views/templates/admin/import.html.twig',
[
'productsCount' => $productsCount,
]
);
Так PHP отвечает за логику, а Twig — за представление.
Современные административные страницы модулей имеют доступ к Twig и остальной Symfony-среде PrestaShop.
Что уже умеет PrestaShopAdminController
Не нужно самостоятельно внедрять каждый базовый компонент PrestaShop.
PrestaShopAdminController предоставляет вспомогательные методы для распространённых задач, включая работу с конфигурацией, переводами, Router и контекстом магазина.
Например:
$value = $this->getConfiguration()->get('MYMODULE_OPTION');
или:
$message = $this->trans(
'Import completed successfully.',
[],
'Modules.Mymodule.Admin'
);
Кроме того, новый контроллер предоставляет методы для выполнения CQRS Commands и Queries.
Получается единая архитектура:
Controller
↓
Command / Query
↓
Handler
↓
Service
↓
Repository / ObjectModel / API
Не забываем про права доступа
Административный Controller нельзя рассматривать просто как скрытый URL.
PrestaShop имеет собственную систему прав сотрудников, поэтому для административных страниц необходимо учитывать разрешения.
В PrestaShop 9 для современных контроллеров используется PHP-атрибут #[AdminSecurity]; старый annotation-вариант заменён в соответствии с современным PHP-подходом.
Это особенно важно для модулей, которые позволяют:
изменять товары;
управлять заказами;
запускать импорт;
изменять цены;
работать с клиентами;
менять настройки интеграций.
Наличие доступа в Back Office ещё не означает, что любой сотрудник должен иметь право выполнить любую операцию.
Как добавить страницу модуля в меню Back Office
Если страница должна появиться в левом меню административной панели, одного routes.yml недостаточно.
PrestaShop связывает меню и права доступа с системой Tab.
Современный Symfony-контроллер можно зарегистрировать через $tabs основного класса модуля и связать его с Symfony route. Для таких страниц PrestaShop также поддерживает _legacy_controller, который помогает связать современную маршрутизацию с системой разрешений Back Office.
То есть современная страница может использовать Symfony, но при этом нормально интегрироваться в существующее меню и систему прав PrestaShop.
Legacy Controller или Symfony Controller?
Полностью отказываться от legacy-контроллеров пока нельзя.
Front Office модулей всё ещё использует ModuleFrontController, а в самой PrestaShop продолжают сосуществовать legacy- и Symfony-компоненты. Официальная документация PrestaShop 9 по-прежнему описывает Front Office-контроллеры через controllers/front/ и ModuleFrontController.
Поэтому на практике архитектура модуля может выглядеть так:
Front Office
↓
ModuleFrontController
Back Office
↓
Symfony Controller
↓
PrestaShopAdminController
Это нормально для текущего этапа развития PrestaShop.
Для новой административной страницы модуля PrestaShop 9 базовая структура выглядит так:
src/Controller/
↓
PrestaShopAdminController
↓
config/routes.yml
↓
Symfony Service
↓
Twig
А бизнес-логика остаётся за пределами Controller:
Controller → Command / Service → бизнес-логика
Такой подход лучше соответствует современной архитектуре PrestaShop, упрощает Dependency Injection и позволяет использовать Symfony Router, Twig, CQRS и систему сервисов без смешивания всей логики в одном административном классе.
Особенно важно не начинать новые модули на FrameworkBundleAdminController: в документации PrestaShop 9 он уже отмечен как deprecated и запланирован к удалению в PrestaShop 10.
Официальная документация: Admin controllers — PrestaShop Developer Documentation