AtroCore's powerful, built-in module system allows you to extend its features. The Listener system is a key part of this, letting your modules modify or change the behavior of existing features, whether they're from the Core itself or other modules like Pim.

This documentation will show you how to define listeners for different components, including entity repositories, controllers, and services.


Entity Repository Listeners

Entity repository listeners allow you to hook into the lifecycle of an entity, such as before it's saved or after it's removed. You can create two types of listeners:

  • General Listeners: A listener that acts on all entity repositories.
  • Specific Listeners: A listener that only acts on a single, specific entity repository.

Creating a General Entity Listener

To create a general listener that applies to all entity repositories, create the file Listeners/Entity.php within your module.

<?php

namespace {ModuleName}\Listeners;

use Atro\Core\EventManager\Event;

class Entity extends AbstractListener
{
    /**
     * @param Event $event The event object
     * @return void
     */
    public function beforeSave(Event $event): void
    {
        // Get the entity object from the event arguments
        $entity = $event->getArgument('entity');

        // Check if the entity is of type 'Product'
        if ($entity->getEntityType() === 'Product') {
            // Modify the 'name' attribute of the product entity
            $entity->set('name', ucfirst($entity->get('name')));

            // Overwrite the original entity in the event with the modified one
            $event->setArgument('entity', $entity);
        }
    }
}

The example above demonstrates a beforeSave event listener that capitalizes the first letter of a Product's name before it is saved to the database.

Creating a Specific Entity Listener

To create a listener for a specific entity type, like Product, create a file named Listeners/{EntityName}Entity.php. For a Product entity, the filename would be Listeners/ProductEntity.php.

<?php

namespace {ModuleName}\Listeners;

use Atro\Core\EventManager\Event;

class ProductEntity extends AbstractListener
{
    /**
     * @param Event $event The event object
     * @return void
     */
    public function beforeSave(Event $event): void
    {
        // Get the entity object from the event arguments
        $entity = $event->getArgument('entity');

        // Modify the 'name' attribute of the product entity
        $entity->set('name', ucfirst($entity->get('name')));

        // Overwrite the original entity in the event with the modified one
        $event->setArgument('entity', $entity);
    }
}

This example achieves the same result as the general listener but is triggered only for the Product entity, making it a more focused approach.

Available Events

Entity listeners can respond to the following events, which are named in the format [action]Save or [action]Remove to indicate when they are triggered:

  • beforeSave
  • afterSave
  • beforeRemove
  • afterRemove
  • beforeRelate
  • afterRelate
  • beforeUnrelate
  • afterUnrelate
  • beforeMassRelate
  • afterMassRelate

Event Arguments

You can retrieve the following arguments from the event object using $event->getArgument('{argumentName}'):

  • entity: The entity object being processed.
  • entityType: The name of the entity (e.g., 'Product').
  • options: Additional options passed to the method.
  • relationName: The name of the relation (for relate/unrelate actions).
  • relationParams: Additional parameters related to the relation.
  • relationData: Data for intermediate relation fields.
  • foreign: The foreign entity ID or object (for relate/unrelate actions).

You can inspect all available arguments by using $event->getArguments().

Controller Listeners

Controller listeners allow you to intercept the execution of controller actions, either before or after they occur. Like entity listeners, you can create general listeners for all controllers or specific ones for a single controller.

Creating a General Controller Listener

To listen to actions for any controller, create the file Listeners/Controller.php.

<?php

namespace {ModuleName}\Listeners;

use Atro\Core\EventManager\Event;

class Controller extends AbstractListener
{
    /**
     * @param Event $event The event object
     * @return void
     */
    public function beforeAction(Event $event): void
    {
        // This method is called before any controller action in the system is executed.
        $data = $event->getArgument('data');
        $params = $event->getArgument('params');
        $request = $event->getArgument('request');
    }

    /**
     * @param Event $event The event object
     * @return void
     */
    public function afterAction(Event $event): void
    {
        // This method is called after any controller action in the system is executed.
        $data = $event->getArgument('data');
        $params = $event->getArgument('params');
        $request = $event->getArgument('request');
        $result = $event->getArgument('result');
    }
}

Creating a Specific Controller Listener

To create a listener for a specific controller, such as the Product controller, create a file named Listeners/{EntityName}Controller.php, which would be Listeners/ProductController.php for this example.

<?php

namespace {ModuleName}\Listeners;

use Atro\Core\EventManager\Event;
use Atro\Listeners\AbstractListener;

class ProductController extends AbstractListener
{
    /**
     * @param Event $event The event object
     * @return void
     */
    public function beforeActionDelete(Event $event): void
    {
        // Get the arguments passed to the delete action.
        $data = $event->getArgument('data');
        $params = $event->getArgument('params') ?? null;
    }
}

This example shows a listener that is only triggered before the delete action is executed on the Product controller, allowing you to perform checks or modifications.

Available Events

Controller listeners can respond to the following events:

  • beforeAction: Triggered before any action.
  • afterAction: Triggered after any action.
  • beforeAction{Action}: Triggered before a specific named action (e.g., beforeActionRead).
  • afterAction{Action}: Triggered after a specific named action.

Common default actions you can listen to include read, create, update, patch, list, delete, createLink, removeLink, follow, unfollow, massUpdate, and massRestore.

Event Arguments

You can retrieve the following arguments from the event:

  • data: An stdClass containing the POST data for the request.
  • request: An instance of the request object, allowing you to get query parameters ($request->get('urlParam')).
  • params: Any parameters passed within the URI.
  • result: The result of the action (only available in afterAction events).

Service Listeners

Service listeners allow you to modify data that is being processed by a service before or after it is sent to the client. This is a powerful way to transform data at the API level.

Creating a General Service Listener

To create a listener that applies to all entity services, create the file Listeners/Service.php.

<?php

namespace Atro\Listeners;

use Atro\Core\EventManager\Event;
use Atro\Core\Utils\Language;

class Service extends AbstractListener
{
    /**
     * @param Event $event The event object
     * @return void
     */
    public function prepareEntityForOutput(Event $event): void
    {
        $entity = $event->getArgument('entity');

        if ($entity->getEntityType() === 'Product') {
            // Transform the product name to uppercase before it's returned by the API
            $entity->set('name', strtoupper($entity->get('name')));
        }
    }
}

In this example, the prepareEntityForOutput event is triggered for any entity, and if that entity is a Product, its name is converted to uppercase.

Creating a Specific Service Listener

To create a listener for a specific service, such as the Product service, create a file named Listeners/{EntityName}Service.php, which would be Listeners/ProductService.php.

<?php

namespace Atro\Listeners;

use Atro\Core\EventManager\Event;

class ProductService extends AbstractListener
{
    /**
     * @param Event $event The event object
     * @return void
     */
    public function prepareEntityForOutput(Event $event): void
    {
        $entity = $event->getArgument('entity');

        // Transform the product name to uppercase before it's returned by the API
        $entity->set('name', strtoupper($entity->get('name')));
    }
}

This example provides a more direct way to modify the Product entity specifically.

Available Events

Here is a breakdown of the available service events, organized by the type of action they correspond to:

Entity Lifecycle Events

These events are triggered during the creation, retrieval, updating, and deletion of a single entity.

  • Creation & Retrieval:
    • beforeCreateEntity
    • afterCreateEntity
    • beforeReadEntity
    • afterReadEntity
    • beforeGetEntity
    • afterGetEntity
  • Modification:
    • beforeUpdateEntity
    • afterUpdateEntity
  • Deletion & Restoration:
    • beforeDeleteEntity
    • afterDeleteEntity
    • beforeRestoreEntity
    • afterRestoreEntity
  • Internal:
    • loadEntityAfterUpdate

Collection & List Events

These events are related to operations on multiple entities, such as finding, listing, or preparing a collection for output.

  • Finding & Listing:
    • beforeFindEntities
    • afterFindEntities
    • beforeGetListKanban
    • afterGetListKanban
  • Output & Display:
    • prepareCollectionForOutput
    • loadPreviewForCollection

These events are triggered when entities are being linked or unlinked from each other.

  • Finding Related Entities:
    • beforeFindLinkedEntities
    • afterFindLinkedEntities
  • Linking & Unlinking:
    • beforeLinkEntity
    • afterLinkEntity
    • beforeLinkEntityMass
    • afterLinkEntityMass
    • beforeUnlinkEntity
    • afterUnlinkEntity
    • beforeUnlinkAll
    • afterUnlinkAll
    • beforeDuplicateLink

Mass Action Events

These events are specifically for actions performed on multiple entities at once.

  • Following & Unfollowing:
    • beforeFollow
    • afterFollow
    • beforeUnfollow
    • afterUnfollow
    • beforeMassFollow
    • afterMassFollow
    • beforeMassUnfollow
    • afterMassUnfollow
  • Updating & Restoring:
    • beforeMassUpdate
    • afterMassUpdate
    • beforeMassRestore

Event Arguments

The arguments available to a service listener vary depending on the specific event. You can always use $event->getArguments() to inspect all available arguments for a given event.

Additional Listeners

AtroCore's listener system also extends to other core components. For more information, please check the following sections in the documentation:

  • Layouts: See the Layout management section for details on extending layouts.
  • Metadata: See the Metadata section for details on programmatic metadata extensions.
  • Language: See the Translations section for details on extending translations.