Events 

Events List 

Datagrids in Oro applications are highly customizable. It is possible to modify an existing grid to fetch more data than initially defined in the grid configuration. To provide extendability points, build and result events have been introduced.

Build Events 

Build events are dispatched by the Builder class right before and immediately after processing the configuration and building datasource. They are helpful in case you need to modify the datagrid or a query configuration.

Four events are dispatched during the build process:

  • Class BuildBefore, event name: oro_datagrid.datagrid.build.before

  • Class BuildBefore, event name: oro_datagrid.datagrid.build.before.DATAGRID_NAME

  • Class BuildAfter, event name: oro_datagrid.datagrid.build.after

  • Class BuildAfter, event name: oro_datagrid.datagrid.build.after.DATAGRID_NAME

BuildBefore Events 

By listening to these events, you can add new elements to the grid configuration or modify the already existing configuration in your event listener. You can use the generic build.before event to listen to all or specific datagrids, which will be called only for the given datagrid - build.before.DATAGRID_NAME.

The BuildBefore event class has access to the DatagridConfiguration instance.

Hint

Please note that at this point datasource has not been initialized yet, therefore calling $event->getDatagrid()->getDatasource() returns null.

As an illustration, let’s add one more column to a specific datagrid. For this, create an event listener and modify the existing configuration in the following way:

namespace Acme\Bundle\DemoBundle\EventListener\Datagrid;

use Oro\Bundle\DataGridBundle\Event\BuildBefore;

class AdditionalColumnDatagridListener
{
    /**
     * @param BuildBefore $event
     * @return void
     */
    public function onBuildBefore(BuildBefore $event): void
    {
        $config = $event->getConfig();
        $config->offsetSetByPath('[columns][myCustomColumn]', ['label' => 'acme.demo.my_custom_column.label']);
        $config->offsetAddToArrayByPath('[source][query][select]', ['123 as myCustomColumn']);
    }
}

Once the listener is created, register it in services.yml:

acme_demo.event_listener.datagrid.additional_column:
    class: Acme\Bundle\DemoBundle\EventListener\Datagrid\AdditionalColumnDatagridListener
    tags:
        - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.before.DATAGRID_NAME, method: onBuildBefore }

Use Cases

  • Add additional columns and update query configuration for the translation datagrid: Oro\Bundle\TranslationBundle\EventListener\Datagrid\LanguageListener

  • Remove public column from the system calendar datagrid: Oro\Bundle\CalendarBundle\EventListener\Datagrid\SystemCalendarGridListener

  • (OroCommerce) Bind user’s currency parameter to the checkout grid: Oro\Bundle\CheckoutBundle\Datagrid\CheckoutGridListener

BuildAfter Events 

You can modify the datasource or even the whole datagrid instance by listening to these events. However, the most common case for this event is to modify the query (add additional joins, selects, the where conditions, etc.).

You can use a generic build.after event for listening to all or specific datagrids, which will be called only for a given datagrid - build.after.DATAGRID_NAME.

The BuildAfter event class has access to Datagrid instance.

For example, let us filter the datagrid by a particular value from the request params. For this, create an event listener and modify the query builder, as illustrated below:

namespace Acme\Bundle\DemoBundle\EventListener\Datagrid;

use Oro\Bundle\DataGridBundle\Datasource\Orm\OrmDatasource;
use Oro\Bundle\DataGridBundle\Event\BuildAfter;
use Symfony\Component\HttpFoundation\RequestStack;

class FilterByRequestParamListener
{
    protected RequestStack $requestStack;

    /**
     * @param RequestStack $requestStack
     */
    public function __construct(RequestStack $requestStack) {
        $this->requestStack = $requestStack;
    }

    /**
     * @param BuildAfter $event
     * @return void
     */
    public function onBuildAfter(BuildAfter $event): void
    {
        $datasource = $event->getDatagrid()->getDatasource();
        if (!$datasource instanceof OrmDatasource) {
            return;
        }

        $customFilter = $this->requestStack->getCurrentRequest()->get('custom_filter');

        $queryBuilder = $datasource->getQueryBuilder();
        $queryBuilder->andWhere($queryBuilder->expr()->eq('some_column', ':custom_filter'));
        $queryBuilder->setParameter('custom_filter', $customFilter);
    }
}

Please note that this example works only for ORM datasources.

Once the listener is created, register it in services.yml:

acme_demo.event_listener.datagrid.filter_by_request_param:
class: Acme\Bundle\DemoBundle\EventListener\Datagrid\FilterByRequestParamListener
arguments:
    - '@request_stack'
tags:
    - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.after.DATAGRID_NAME, method: onBuildAfter }

Use Cases

  • Apply additional filtering to the activity email grid: Oro\Bundle\EmailBundle\EventListener\Datagrid\ActivityGridListener

  • (OroCommerce) Add additional properties to the storefront product grid: Oro\Bundle\CatalogBundle\EventListener\SearchCategoryFilteringEventListener

Result Events 

Result events are type-specific, which means that datasource is responsible for dispatching them. Listening to these events is useful both when you need to access a query (e.g., ORM, search) and modify the results.

As an example, have a look at the OrmDatasource. In the getResult() method it dispatches 4 main and 2 additional events:

  • Additional - Class OrmResultBeforeQuery, event name: oro_datagrid.orm_datasource.result.before_query

  • Additional - Class OrmResultBeforeQuery, event name: oro_datagrid.orm_datasource.result.before_query.DATAGRID_NAME

  • Main - Class OrmResultBefore, event name: oro_datagrid.orm_datasource.result.before

  • Main - Class OrmResultBefore, event name: oro_datagrid.orm_datasource.result.before.DATAGRID_NAME

  • Main - Class OrmResultAfter, event name: oro_datagrid.orm_datasource.result.after

  • Main - Class OrmResultAfter, event name: oro_datagrid.orm_datasource.result.after.DATAGRID_NAME

The first four events are mostly used to access a query at different stages, while the last two are used to modify the results.

Remember to dispatch result events when creating your own custom datasource type.

ResultBefore Events 

The purpose of these events is to have the ability to access datagrid or a query instance before the datasource starts building the results. You can use generic result.before event for listening to all or specific datagrids, which will be called only for a given datagrid - result.before.DATAGRID_NAME.

Use Cases

  • Apply ACL to a datagrid datasource: Oro\Bundle\DataGridBundle\EventListener\OrmDatasourceAclListener

ResultAfter Events 

The purpose of these events is to have ability to modify data after the rows were fetched from the datasource. You can use generic result.after event for listening to all or specific datagrids, which will be called only for a given datagrid - result.after.DATAGRID_NAME.

For instance, if you have complex data that is hard to process with the standard datagrid configuration using YML files, you can create an event listener and fetch the data once the rows are fetched from the datasource.

namespace Acme\Bundle\DemoBundle\EventListener\Datagrid;

use Oro\Bundle\DataGridBundle\Datasource\ResultRecord;
use Oro\Bundle\DataGridBundle\Event\OrmResultAfter;

class ComplexDataDatagridListener
{
    /**
     * @param OrmResultAfter $event
     * @return void
     */
    public function onResultAfter(OrmResultAfter $event): void
    {
        /** @var ResultRecord[] $records */
        $records = $event->getRecords();

        $complexData = $this->complexService->getComplexDataForRecords($records);

        foreach ($records as $record) {
            $recordId = $record->getValue('id');
            $record->addData(['complexData' => $complexData[$recordId]]);
        }
    }
}

Once the event listener is created, register it in services.yml:

acme_demo.event_listener.datagrid.complex_data:
    class: Acme\Bundle\DemoBundle\EventListener\Datagrid\ComplexDataDatagridListener
    tags:
        - { name: kernel.event_listener, event: oro_datagrid.orm_datasource.result.after.DATAGRID_NAME, method: onResultAfter }

Use Cases

  • Translate workflow fields in the email notification grid: Oro\Bundle\WorkflowBundle\Datagrid\EmailNotificationDatagridListener

  • (OroCommerce) Add payment methods to the order grid: Oro\Bundle\OrderBundle\EventListener\OrderDatagridListener