🗂️
Symfony Controllers y Tabs en el BO de PrestaShop 8/9
Actualizado: 2024-12-01
PrestaShop 8+ permite crear paginas de administracion modernas usando Symfony Controllers integrados en el menu lateral del BO. Los Tabs (entradas de menu) se declaran directamente en el modulo y se instalan/desinstalan automaticamente con el modulo.
#Declarar tabs en el constructor del modulo
mymodule.php — declaracion de tabs en el constructor
php
<?php
public function __construct()
{
$this->name = 'mymodule';
$this->tab = 'administration';
$this->version = '1.0.0';
$this->author = 'gmartos.es';
$this->need_instance = 0;
$this->bootstrap = true;
parent::__construct();
// Tabs declarados aqui se instalan/desinstalan con install()/uninstall()
$this->tabs = [
[
'route_name' => 'admin_mymodule_index', // nombre de la ruta
'class_name' => 'AdminMyModuleMain', // class del Tab en DB
'visible' => true, // visible en el menu
'name' => [
'en' => 'My Module',
'es' => 'Mi Modulo',
],
'icon' => 'extension', // icono Material de Google
'parent_class_name' => 'IMPROVE', // padre: SELL, IMPROVE, CONFIGURE, DEFAULT
],
// Tab hijo (submenu sin url propia — solo agrupa)
[
'route_name' => 'admin_mymodule_configure',
'class_name' => 'AdminMyModuleConfigure',
'visible' => true,
'name' => ['en' => 'Configuration', 'es' => 'Configuracion'],
'parent_class_name' => 'AdminMyModuleMain', // hijo del tab anterior
],
];
}
#Instalacion manual de tabs (avanzado)
Instalar un tab manualmente desde install()
php
<?php
private function installTab(string $className, string $routeName, string $parentClassName = 'IMPROVE'): bool
{
// Si ya existe, actualizarlo
$tabId = (int) Tab::getIdFromClassName($className);
$tab = new Tab($tabId ?: null);
$tab->active = 1;
$tab->class_name = $className;
$tab->route_name = $routeName;
$tab->module = $this->name;
$tab->id_parent = (int) Tab::getIdFromClassName($parentClassName);
foreach (Language::getLanguages() as $lang) {
$tab->name[$lang['id_lang']] = $this->trans(
'Mi Modulo',
[],
'Modules.Mymodule.Admin',
$lang['locale']
);
}
return (bool) $tab->save();
}
private function uninstallTab(string $className): bool
{
$tabId = (int) Tab::getIdFromClassName($className);
if ($tabId) {
$tab = new Tab($tabId);
return (bool) $tab->delete();
}
return true;
}
#Crear el Symfony Controller
src/Controller/Admin/ConfigurationController.php
php
<?php
declare(strict_types=1);
namespace MyModule\Controller\Admin;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use PrestaShopBundle\Security\Annotation\AdminSecurity;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ConfigurationController extends FrameworkBundleAdminController
{
public const TAB_CLASS_NAME = 'AdminMyModuleConfigure';
/**
* @AdminSecurity("is_granted('read', request.get('_legacy_controller'))")
*/
public function indexAction(Request $request): Response
{
return $this->render(
'@Modules/mymodule/views/templates/admin/configure.html.twig',
[
'layoutTitle' => $this->trans('Configuracion', 'Modules.Mymodule.Admin'),
'enableSidebar' => true,
'help_link' => $this->generateSidebarLink($request->attributes->get('_legacy_controller')),
]
);
}
}
#Configurar las rutas (routes.yml)
config/routes.yml — definicion de rutas del modulo
yaml
admin_mymodule_index:
path: /my-module
methods: [GET]
defaults:
_controller: 'MyModule\Controller\Admin\DashboardController::indexAction'
_legacy_classname: AdminMyModuleMain
_legacy_link: AdminMyModuleMain
admin_mymodule_configure:
path: /my-module/configure
methods: [GET, POST]
defaults:
_controller: 'MyModule\Controller\Admin\ConfigurationController::indexAction'
_legacy_classname: AdminMyModuleConfigure
_legacy_link: AdminMyModuleConfigure
# Ruta con parametro
admin_mymodule_item_edit:
path: /my-module/item/{id}/edit
methods: [GET, POST]
requirements:
id: '\d+'
defaults:
_controller: 'MyModule\Controller\Admin\ItemController::editAction'
#Plantilla Twig para el BO
views/templates/admin/configure.html.twig
twig
{% extends '@PrestaShop/Admin/layout.html.twig' %}
{% block content %}
<div class="card">
<div class="card-header">
<h3>{{ 'Configuration'|trans({}, 'Modules.Mymodule.Admin') }}</h3>
</div>
<div class="card-body">
{# Renderizar el form Symfony si lo pasas desde el Controller #}
{% if form is defined %}
{{ form_start(form) }}
{{ form_widget(form) }}
<button type="submit" class="btn btn-primary">
{{ 'Save'|trans({}, 'Admin.Actions') }}
</button>
{{ form_end(form) }}
{% endif %}
</div>
</div>
{% endblock %}
Padres de menu disponibles
Los valores validos para parent_class_name son: SELL (vender), IMPROVE (mejorar), CONFIGURE (configurar), DEFAULT (raiz), o el class_name de otro tab del modulo para crear submenus.
Descargar en Markdown
Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.