How to work with the Search Form

The grid component allows to filter its content, to manage the filtering you will need to define the following elements:

  • GridDefinition::getFilters
  • Filters class
  • Controllers:
    • Search action
    • List action
    • Reset filter action

Add Filters into GridDefinition

<?php
final class EmailLogsDefinitionFactory extends AbstractGridDefinitionFactory
{
    /**
     * @param string $resetActionUrl
     * @param string $redirectionUrl
     */
    public function __construct($resetActionUrl, $redirectionUrl)
    {
        $this->resetActionUrl = $resetActionUrl;
        $this->redirectionUrl = $redirectionUrl;
    }

    /**
     * {@inheritdoc}
     */
    protected function getId()
    {
        return 'email_logs';
    }

    ...
    /**
    * {@inheritdoc}
    */
    protected function getFilters()
    {
        return (new FilterCollection())
            ->add((new Filter('id_meta', TextType::class))
                ->setTypeOptions([
                    'required' => false,
                ])
                ->setAssociatedColumn('id_meta')
            )
            ->add((new Filter('page', TextType::class))
                ->setTypeOptions([
                    'required' => false,
                ])
                ->setAssociatedColumn('page')
            )
            ->add((new Filter('title', TextType::class))
                ->setTypeOptions([
                    'required' => false,
                ])
                ->setAssociatedColumn('title')
            )
            ->add((new Filter('url_rewrite', TextType::class))
                ->setTypeOptions([
                    'required' => false,
                ])
                ->setAssociatedColumn('url_rewrite')
            )
            ->add((new Filter('actions', SearchAndResetType::class))
                ->setTypeOptions([
                    'attr' => [
                        'data-url' => $this->resetActionUrl,
                        'data-redirect' => $this->redirectionUrl,
                    ],
                ])
                ->setAssociatedColumn('actions')
            )
        ;
    }
    ...
}

And here is the service definition associated

    prestashop.core.grid.definition.factory.email_logs:
        class: 'PrestaShop\PrestaShop\Core\Grid\Definition\Factory\EmailLogsDefinitionFactory'
        parent: 'prestashop.core.grid.definition.factory.abstract_grid_definition'
        arguments:
            - "@=service('router').generate('admin_common_reset_search', {'controller': 'email', 'action': 'index'})"
            - "@=service('router').generate('admin_emails_index')"
        public: true

The filters types

In the filters collection you define all the available filters (which will match your grid columns), you can define a specific type depending on the column. You can basically use any Symfony form type (including your custom ones) and PrestaShop provides a few filter types that might be useful to you.

Filters class

You need to define a Filters class linked to your Grid, it will allow you to define the default filters and sorting values. It will also make your list action simpler as PrestaShop provides a parameter resolver responsible of automatically create and fill a Filters object.

<?php
use PrestaShop\PrestaShop\Core\Search\Filters;

/**
 * Class EmailLogsFilter defines default filters for Email logs grid.
 */
final class EmailLogsFilter extends Filters
{
    /**
     * {@inheritdoc}
     */
    public static function getDefaults()
    {
        return [
            'limit' => 50,
            'offset' => 0,
            'orderBy' => 'id_mail',
            'sortOrder' => 'desc',
            'filters' => [],
        ];
    }
}

Controller actions

The Grid filtering workflow is divided into three controllers:

  • search action: it parses the filters from the POST request, then redirects to the list action
  • list action: it parses the filters from GET request, persists them into database and finally renders the grid
  • reset action: to clean the persisted filters and reset to the default ones

Search action

<?php
class EmailController extends FrameworkBundleAdminController
{
    ...
    /**
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))", message="Access denied.")
     *
     * @param Request $request
     *
     * @return RedirectResponse
     */
    public function searchAction(Request $request)
    {
        $definitionFactory = $this->get('prestashop.core.grid.definition.factory.email_logs');
        $emailLogsDefinition = $definitionFactory->getDefinition();

        $gridFilterFormFactory = $this->get('prestashop.core.grid.filter.form_factory');
        $filtersForm = $gridFilterFormFactory->create($emailLogsDefinition);
        $filtersForm->handleRequest($request);

        $filters = [];

        if ($filtersForm->isSubmitted()) {
            $filters = $filtersForm->getData();
        }

        return $this->redirectToRoute('admin_emails_index', ['filters' => $filters]);
    }
    ...
}
# Routing
admin_emails_search:
    path: /
    methods: [POST]
    defaults:
        _controller: 'PrestaShopBundle:Admin\Configure\AdvancedParameters\Email:search'
        _legacy_controller: AdminEmails

List action

Thanks to the internal parameter resolver you can directly use your Filters class as an argument in the controller. It then automatically:

  • parses the potential parameters in the query and fills them into the Filters argument
  • matches thanks to the class the filters from the database and fetch them if present
  • persists the filters in the database
<?php
class EmailController extends FrameworkBundleAdminController
{
    ...
    /**
     * Show email configuration page.
     *
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))", message="Access denied.")
     *
     * @param Request $request
     * @param EmailLogsFilter $filters
     *
     * @return Response
     */
    public function indexAction(Request $request, EmailLogsFilter $filters)
    {
        $emailLogsGridFactory = $this->get('prestashop.core.grid.factory.email_logs');
        $emailLogsGrid = $emailLogsGridFactory->getGrid($filters);
        $presentedEmailLogsGrid = $this->presentGrid($emailLogsGrid);

        return $this->render('@PrestaShop/Admin/Configure/AdvancedParameters/Email/index.html.twig', [
            'enableSidebar' => true,
            'emailLogsGrid' => $presentedEmailLogsGrid,
            'help_link' => $this->generateSidebarLink($request->attributes->get('_legacy_controller')),
        ]);
    }
    ...
}

Reset action

Last action is used to reset the persisted filters and your grid filtering/sorting. This action is the same for nearly all grids so PrestaShop provides a common controller to manage it, and you actually already set it via the grid definition.

It is defined in the service definition, it uses the admin_common_reset_search route and use email/index as keys to match the controller/action.

    prestashop.core.grid.definition.factory.email_logs:
        class: 'PrestaShop\PrestaShop\Core\Grid\Definition\Factory\EmailLogsDefinitionFactory'
        parent: 'prestashop.core.grid.definition.factory.abstract_grid_definition'
        arguments:
            - "@=service('router').generate('admin_common_reset_search', {'controller': 'email', 'action': 'index'})"
            - "@=service('router').generate('admin_emails_index')"
        public: true