Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Extending back office grids and forms

Symfony back office pages are built from two bricks: a grid with a list and a form. A module can extend someone else's grid or form — add a column to the customers list, a field to the customer form. For that every grid and form has a set of action hooks whose names follow a pattern.

Grid hooks

HookWhat it lets you change
action<Name>GridDefinitionModifierThe set of columns, filters and actions
action<Name>GridQueryBuilderModifierThe SQL query that selects the rows
action<Name>GridDataModifierThe rows already selected

<Name> is the grid id: Customer, Order, Category, Address. For the customers list the hooks are called actionCustomerGridDefinitionModifier and actionCustomerGridQueryBuilderModifier.

A column in the customers list

Let us add a "Reviews" column to the customers list. First the column description:

// modules/acmehello/acmehello.php
use PrestaShop\PrestaShop\Core\Grid\Column\Type\DataColumn;
 
public function hookActionCustomerGridDefinitionModifier(array $params): void
{
    $column = new DataColumn('reviews_count');
    $column->setName($this->trans('Reviews', [], 'Modules.Acmehello.Admin'));
    $column->setOptions(['field' => 'reviews_count']);
 
    $params['definition']->getColumns()->addAfter('email', $column);
}

The use line goes at the top of the file, before the class declaration. $params['definition'] holds the grid description. addAfter('email', ...) inserts the column after the email column, and the field option says which field of a row holds the value.

The value for the column

The query has no reviews_count field yet. The second hook adds it:

// modules/acmehello/acmehello.php
public function hookActionCustomerGridQueryBuilderModifier(array $params): void
{
    $params['search_query_builder']->addSelect(
        '(SELECT COUNT(*) FROM `' . _DB_PREFIX_ . 'acmehello_review` r
          WHERE r.id_customer = c.id_customer) AS reviews_count'
    );
}

search_query_builder is the Doctrine query builder the grid uses to select customers; the customers table has the alias c in it. The subquery counts each customer's reviews by the id_customer column added in the lesson on tables.

How to see the result

Register both hooks in install() and reset the module:

&& $this->registerHook('actionCustomerGridDefinitionModifier')
&& $this->registerHook('actionCustomerGridQueryBuilderModifier')
php bin/console prestashop:module reset acmehello

Open "Customers → Customers": after the email column there is a "Reviews" column with a number for every customer.

Form hooks

HookWhen it fires
action<Name>FormBuilderModifierThe form is being built — a field can be added
actionAfterCreate<Name>FormHandlerA new record is saved
actionAfterUpdate<Name>FormHandlerAn existing record is saved

A field in the customer form

// modules/acmehello/acmehello.php
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
 
public function hookActionCustomerFormBuilderModifier(array $params): void
{
    $params['form_builder']->add('acme_trusted', CheckboxType::class, [
        'label' => $this->trans('Trusted review author', [], 'Modules.Acmehello.Admin'),
        'required' => false,
    ]);
 
    $params['data']['acme_trusted'] = (bool) Configuration::get('ACMEHELLO_TRUSTED_' . (int) $params['id']);
    $params['form_builder']->setData($params['data']);
}

form_builder is the Symfony form builder. The add() method adds a checkbox, and setData() fills in its current value. $params['id'] holds the customer id; it is empty when a new customer is being created.

Saving the field

// modules/acmehello/acmehello.php
public function hookActionAfterUpdateCustomerFormHandler(array $params): void
{
    Configuration::updateValue(
        'ACMEHELLO_TRUSTED_' . (int) $params['id'],
        (int) !empty($params['form_data']['acme_trusted'])
    );
}

form_data holds the values of all form fields, including the added one. Here the checkbox is kept in Configuration for simplicity; a real module would add a column to its own table for that. After registering the three hooks and resetting the module, the customer form shows the checkbox and keeps its state.

Common mistake

A column is added to the grid definition, but the query is not changed. The list page fails with an unknown field error or shows an empty column. The GridDefinitionModifier and GridQueryBuilderModifier hooks almost always come as a pair: the first declares the column, the second supplies its data.

Thanks for reading!

Donate to the site — we work hard for you.