📊 Grid System moderno en PS 1.7+ — referencia
Actualizado: 2024-12-01
El Grid System de PrestaShop 1.7+ reemplaza al HelperList con una arquitectura mas moderna y extensible. Se basa en cuatro componentes: Definition (estructura), DataProvider (datos), QueryBuilder (query SQL) y GridFactory (renderizado final).
#Arquitectura del Grid System
| Componente | Clase base / Interfaz | Responsabilidad |
|---|---|---|
| GridDefinition | AbstractGridDefinition | Columnas, filtros, acciones del grid |
| GridQueryBuilder | AbstractDoctrineQueryBuilder | Query DBAL para datos y count |
| GridDataProvider | DoctrineGridDataProvider | Conecta Definition y QueryBuilder |
| GridFactory | GridFactory (core) | Construye el objeto Grid final |
| Grid en Twig | @PrestaShop/Admin/Common/Grid/ | Template que renderiza el grid |
#GridDefinitionFactory
src/Grid/Definition/MyItemGridDefinitionFactory.php
php
<?php
declare(strict_types=1);
namespace MyModule\Grid\Definition;
use PrestaShop\PrestaShop\Core\Grid\Action\Row\RowActionCollection;
use PrestaShop\PrestaShop\Core\Grid\Action\Row\Type\LinkRowAction;
use PrestaShop\PrestaShop\Core\Grid\Action\Bulk\BulkActionCollection;
use PrestaShop\PrestaShop\Core\Grid\Action\Bulk\Type\SubmitBulkAction;
use PrestaShop\PrestaShop\Core\Grid\Column\ColumnCollection;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\DataColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ToggleColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ActionColumn;
use PrestaShop\PrestaShop\Core\Grid\Definition\Factory\AbstractGridDefinitionFactory;
use PrestaShop\PrestaShop\Core\Grid\Filter\Filter;
use PrestaShop\PrestaShop\Core\Grid\Filter\FilterCollection;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class MyItemGridDefinitionFactory extends AbstractGridDefinitionFactory
{
protected function getId(): string
{
return 'my_module_items';
}
protected function getName(): string
{
return 'Items de Mi Modulo';
}
protected function getColumns(): ColumnCollection
{
return (new ColumnCollection())
->add((new DataColumn('id_mymodule_item'))
->setName('ID')
->setOptions(['field' => 'id_mymodule_item']))
->add((new DataColumn('name'))
->setName('Nombre')
->setOptions(['field' => 'name']))
->add((new ToggleColumn('active'))
->setName('Activo')
->setOptions([
'field' => 'active',
'primary_field' => 'id_mymodule_item',
'route' => 'admin_mymodule_item_toggle',
'route_param_name' => 'id',
]))
->add((new ActionColumn('actions'))
->setName('Acciones')
->setOptions([
'actions' => (new RowActionCollection())
->add((new LinkRowAction('edit'))
->setName('Editar')
->setIcon('edit')
->setOptions([
'route' => 'admin_mymodule_item_edit',
'route_param_name' => 'id',
'route_param_field'=> 'id_mymodule_item',
]))
->add((new LinkRowAction('delete'))
->setName('Eliminar')
->setIcon('delete')
->setOptions([
'route' => 'admin_mymodule_item_delete',
'route_param_name' => 'id',
'route_param_field'=> 'id_mymodule_item',
'confirm_message' => '¿Eliminar este item?',
]))
]));
}
protected function getFilters(): FilterCollection
{
return (new FilterCollection())
->add((new Filter('name', TextType::class))
->setTypeOptions(['required' => false, 'attr' => ['placeholder' => 'Buscar por nombre...']])
->setAssociatedColumn('name'))
->add((new Filter('active', ChoiceType::class))
->setTypeOptions([
'required' => false,
'choices' => ['Activo' => '1', 'Inactivo' => '0', 'Todos' => ''],
])
->setAssociatedColumn('active'));
}
protected function getBulkActions(): BulkActionCollection
{
return (new BulkActionCollection())
->add((new SubmitBulkAction('delete_selection'))
->setName('Eliminar seleccionados')
->setOptions(['submit_route' => 'admin_mymodule_items_bulk_delete', 'confirm_message' => '¿Eliminar?']));
}
}
#Column types disponibles
| Tipo | Clase | Uso |
|---|---|---|
| DataColumn | Core\Grid\Column\Type\DataColumn | Texto generico |
| ToggleColumn | Common\ToggleColumn | Switch activo/inactivo |
| ImageColumn | Common\ImageColumn | Imagen miniatura |
| LinkColumn | Common\LinkColumn | Enlace clicable |
| ColorColumn | Common\ColorColumn | Muestra color hex |
| DateTimeColumn | Common\DateTimeColumn | Fecha formateada |
| BadgeColumn | Common\BadgeColumn | Badge con color |
| ActionColumn | Common\ActionColumn | Columna de acciones por fila |
#GridQueryBuilder
src/Grid/Query/MyItemQueryBuilder.php
php
<?php
declare(strict_types=1);
namespace MyModule\Grid\Query;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use PrestaShop\PrestaShop\Core\Grid\Query\AbstractDoctrineQueryBuilder;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
class MyItemQueryBuilder extends AbstractDoctrineQueryBuilder
{
private string $dbPrefix;
public function __construct(Connection $connection, string $dbPrefix)
{
parent::__construct($connection);
$this->dbPrefix = $dbPrefix;
}
public function getSearchQueryBuilder(SearchCriteriaInterface $searchCriteria): QueryBuilder
{
$qb = $this->buildBaseQuery();
$qb->select('i.id_mymodule_item, i.name, i.active, i.date_add');
// Aplicar filtros
$this->applyFilters($qb, $searchCriteria);
$this->applySorting($qb, $searchCriteria);
$this->applyPagination($qb, $searchCriteria);
return $qb;
}
public function getCountQueryBuilder(SearchCriteriaInterface $searchCriteria): QueryBuilder
{
$qb = $this->buildBaseQuery();
$qb->select('COUNT(i.id_mymodule_item) AS total');
$this->applyFilters($qb, $searchCriteria);
return $qb;
}
private function buildBaseQuery(): QueryBuilder
{
return $this->connection
->createQueryBuilder()
->from($this->dbPrefix . 'mymodule_item', 'i');
}
private function applyFilters(QueryBuilder $qb, SearchCriteriaInterface $criteria): void
{
foreach ($criteria->getFilters() as $field => $value) {
if ($value === '' || $value === null) continue;
if ($field === 'name') {
$qb->andWhere('i.name LIKE :name')
->setParameter('name', '%' . $value . '%');
} elseif ($field === 'active') {
$qb->andWhere('i.active = :active')
->setParameter('active', (int) $value);
}
}
}
}
Descargar en Markdown
Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.