📊 Grid System — demo_grid + demoextendgrid
#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+.
github.com/PrestaShop/example-modules/tree/master/demo_grid
#GridDefinition y columnas
<?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
<?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
<?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.
github.com/PrestaShop/example-modules/tree/master/demoextendgrid
#Anadir row action a grid existente
<?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
<?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;
}
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