📊 Grid System — demo_grid + demoextendgrid

Actualizado: 2026-04

#demo_grid — Crear un Grid completo

Demuestra como usar el Grid System de PrestaShop para crear listados en el BO con filtros, paginacion, ordenacion y acciones. Requiere PS 9.0.0+.

ℹ️
Repositorio

github.com/PrestaShop/example-modules/tree/master/demo_grid

#GridDefinition y columnas

Definir la estructura del grid
php
<?php
// src/Grid/Definition/Factory/DemoGridDefinitionFactory.php

use PrestaShop\PrestaShop\Core\Grid\Definition\Factory\AbstractGridDefinitionFactory;
use PrestaShop\PrestaShop\Core\Grid\Column\ColumnCollection;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ActionColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\BulkActionColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\Common\ToggleColumn;
use PrestaShop\PrestaShop\Core\Grid\Column\Type\DataColumn;
use PrestaShop\PrestaShop\Core\Grid\Action\Row\Type\LinkRowAction;
use PrestaShop\PrestaShop\Core\Grid\Action\Bulk\Type\SubmitBulkAction;

class DemoGridDefinitionFactory extends AbstractGridDefinitionFactory
{
    const GRID_ID = 'demo_grid';

    protected function getId(): string
    {
        return self::GRID_ID;
    }

    protected function getName(): string
    {
        return $this->trans('Demo items', [], 'Modules.DemoGrid.Admin');
    }

    protected function getColumns(): ColumnCollection
    {
        return (new ColumnCollection())
            ->add((new BulkActionColumn('bulk'))
                ->setOptions(['bulk_field' => 'id_demo'])
            )
            ->add((new DataColumn('id_demo'))
                ->setName('ID')
                ->setOptions(['field' => 'id_demo'])
            )
            ->add((new DataColumn('name'))
                ->setName('Name')
                ->setOptions(['field' => 'name'])
            )
            ->add((new ToggleColumn('active'))
                ->setName('Status')
                ->setOptions([
                    'field'      => 'active',
                    'primary_field' => 'id_demo',
                    'route'      => 'demo_grid_toggle_status',
                    'route_param_name' => 'demoId',
                ])
            )
            ->add((new ActionColumn('actions'))
                ->setName('Actions')
                ->setOptions([
                    'actions' => [
                        (new LinkRowAction('edit'))
                            ->setName('Edit')
                            ->setIcon('edit')
                            ->setOptions([
                                'route' => 'demo_grid_edit',
                                'route_param_name' => 'demoId',
                                'route_param_field' => 'id_demo',
                            ]),
                    ],
                ])
            );
    }

    protected function getBulkActions()
    {
        return (new BulkActionCollection())
            ->add((new SubmitBulkAction('delete_selection'))
                ->setName('Delete selected')
                ->setOptions([
                    'submit_route' => 'demo_grid_bulk_delete',
                ])
            );
    }
}

#DataProvider con DbQuery

QueryBuilder para el grid
php
<?php
// src/Grid/Query/DemoQueryBuilder.php

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
use PrestaShop\PrestaShop\Core\Grid\Query\AbstractDoctrineQueryBuilder;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;

class DemoQueryBuilder extends AbstractDoctrineQueryBuilder
{
    public function getSearchQueryBuilder(SearchCriteriaInterface $searchCriteria): QueryBuilder
    {
        $qb = $this->connection->createQueryBuilder()
            ->select('d.id_demo, d.name, d.active')
            ->from($this->dbPrefix . 'demo_item', 'd');

        // Aplicar filtros
        foreach ($searchCriteria->getFilters() as $filterName => $filterValue) {
            if ($filterName === 'name') {
                $qb->andWhere('d.name LIKE :name')
                   ->setParameter('name', '%' . $filterValue . '%');
            }
            if ($filterName === 'active') {
                $qb->andWhere('d.active = :active')
                   ->setParameter('active', $filterValue);
            }
        }

        // Ordenacion
        if ($searchCriteria->getOrderBy()) {
            $qb->orderBy(
                'd.' . $searchCriteria->getOrderBy(),
                $searchCriteria->getOrderWay()
            );
        }

        // Paginacion
        $qb->setFirstResult($searchCriteria->getOffset())
           ->setMaxResults($searchCriteria->getLimit());

        return $qb;
    }

    public function getCountQueryBuilder(SearchCriteriaInterface $searchCriteria): QueryBuilder
    {
        $qb = $this->connection->createQueryBuilder()
            ->select('COUNT(d.id_demo)')
            ->from($this->dbPrefix . 'demo_item', 'd');

        // Aplicar mismos filtros que en search
        foreach ($searchCriteria->getFilters() as $filterName => $filterValue) {
            if ($filterName === 'name') {
                $qb->andWhere('d.name LIKE :name')
                   ->setParameter('name', '%' . $filterValue . '%');
            }
        }

        return $qb;
    }
}

#Filtros y busqueda

FilterForm para el grid
php
<?php
// src/Grid/Filters/DemoFilters.php

use PrestaShop\PrestaShop\Core\Grid\Filter\Filter;
use PrestaShop\PrestaShop\Core\Search\Filters;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;

class DemoFilters extends Filters
{
    protected $filterId = 'demo_grid';

    public static function getDefaults(): array
    {
        return [
            'limit'    => 10,
            'offset'   => 0,
            'orderBy'  => 'id_demo',
            'orderWay' => 'DESC',
            'filters'  => [],
        ];
    }
}

// Registrar filtros en services.yml:
// services:
//   prestashop.module.demo_grid.filters:
//     class: DemoFilters
//     tags:
//       - { name: 'prestashop.core.grid.filter_form' }

#demoextendgrid — Extender grid existente

Demuestra como anadir una row action a un grid existente del BO (ej: grid de productos, pedidos, clientes) y como registrar JavaScript en un admin controller.

ℹ️
Repositorio

github.com/PrestaShop/example-modules/tree/master/demoextendgrid

#Anadir row action a grid existente

Hook actionProductGridDefinitionModifier
php
<?php
public function hookActionProductGridDefinitionModifier(array $params): void
{
    /** @var \PrestaShop\PrestaShop\Core\Grid\Definition\GridDefinitionInterface $definition */
    $definition = $params['definition'];

    // Anadir columna de accion al grid de productos
    $definition->getColumns()
        ->addAfter('actions', (new DataColumn('my_custom_field'))
            ->setName('Mi campo')
            ->setOptions(['field' => 'my_custom_field'])
        );

    // O anadir una row action al ActionColumn existente
    /** @var ActionColumn $actionsColumn */
    $actionsColumn = $definition->getColumns()->get('actions');
    $actionsColumn->getOptions()['actions']->add(
        (new LinkRowAction('my_action'))
            ->setName('Mi accion')
            ->setIcon('star')
            ->setOptions([
                'route' => 'my_module_custom_action',
                'route_param_name' => 'productId',
                'route_param_field' => 'id_product',
            ])
    );
}

// Tambien modificar el QueryBuilder para incluir datos:
public function hookActionProductGridQueryBuilderModifier(array $params): void
{
    /** @var QueryBuilder $searchQueryBuilder */
    $searchQueryBuilder = $params['search_query_builder'];

    $searchQueryBuilder->addSelect('mc.my_custom_field')
        ->leftJoin(
            'p',
            $this->dbPrefix . 'my_custom_table',
            'mc',
            'mc.id_product = p.id_product'
        );
}

#Registrar JS en admin controller

Inyectar JavaScript en pagina de admin
php
<?php
// Registrar JS en la pagina de productos del BO
public function hookActionAdminControllerSetMedia(): void
{
    // Solo en la pagina de productos
    if ($this->isProductPage()) {
        $this->context->controller->addJS(
            $this->getPathUri() . 'views/js/grid-extension.js'
        );
    }
}

private function isProductPage(): bool
{
    $controller = Tools::getValue('controller');
    $route = Tools::getValue('_route');
    
    return $controller === 'AdminProducts'
        || strpos($route, 'admin_product') === 0;
}
💡
Hooks de grid disponibles

Cada grid del BO tiene hooks para modificar su definicion, query y datos: - action{GridId}GridDefinitionModifier — columnas, acciones, filtros - action{GridId}GridQueryBuilderModifier — SQL query - action{GridId}GridDataModifier — datos ya obtenidos - action{GridId}GridFilterFormModifier — formulario de filtros - action{GridId}GridPresenterModifier — presentacion final

Descargar en Markdown Pensado para pegar en ChatGPT, Claude u otra IA. Incluye solo el contenido de esta pagina.