rubenmartindev/prestashop-module-hook-bus

Flexible and centralized way to route and handle PrestaShop hooks

Maintainers

Package info

github.com/rubenmartindev/prestashop-module-hook-bus

pkg:composer/rubenmartindev/prestashop-module-hook-bus

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-06-04 15:30 UTC

This package is auto-updated.

Last update: 2026-06-04 15:43:41 UTC


README

This library provides a flexible and centralized way to route and handle PrestaShop hooks.

Overview

As you develop your module and add hooks to the main file, the module can grow disproportionately; all logic ends up in a single place, breaking the SOLID Single Responsibility principle and making maintenance and readability chaotic.

Ideally, each hook should be self-contained and have a single responsibility. Making it easy to configure, use, and maintain.

Compared to managing hooks directly in your module's main class, Hook Bus offers:

  • Better separation of concerns.
  • Easier testing.
  • Cleaner module classes.
  • Dependency Injection friendly handlers.
  • Reusable hook logic.

The library is composed of three main building blocks:

  • Identifier: determines the hook identity.
  • Locator: resolves the Handler for that identity.
  • Handler: contains the hook business logic.

Requirements

  • PHP 5.6+
  • PrestaShop 1.6.x / 1.7.x / 8.x / 9.x+

Installation

Install via Composer in your PrestaShop module:

composer require rubenmartindev/prestashop-module-hook-bus

Complete Example

A typical module structure could look like this:

modules/
└── mymodule/
    ├── mymodule.php
    └── src/
        └── Hook/
            ├── DisplayHeaderHandler.php
            └── DisplayFooterHandler.php

Configure the Hook Bus once in the module constructor:

use RubenMartinDev\PrestashopModuleHookBus\HookBusFactory;
use RubenMartinDev\PrestashopModuleHookBus\HookBusInterface;
use RubenMartinDev\PrestashopModuleHookBus\Identifier\MethodHookIdentifier;

class MyModule extends Module
{
    /** @var HookBusInterface */
    private $hookBus;

    public function __construct()
    {
        // ...

        $this->hookBus = HookBusFactory::createWithArray(
            new MethodHookIdentifier(),
            [
                new DisplayHeaderHandler(),
                new DisplayFooterHandler(),
            ]
        );
    }

    public function hookDisplayHeader(array $params)
    {
        return $this->hookBus->dispatch(__FUNCTION__, $params);
    }

    public function hookDisplayFooter(array $params)
    {
        return $this->hookBus->dispatch(__FUNCTION__, $params);
    }
}

Each hook is implemented in its own Handler:

use RubenMartinDev\PrestashopModuleHookBus\Handler\NamedHandlerInterface;

final class DisplayHeaderHandler implements NamedHandlerInterface
{
    public static function getIdentityName()
    {
        return 'displayHeader';
    }

    public function handle(array $params = [])
    {
        // Hook logic here
    }
}

Factory

To make configuring and creating the Hook Bus easier, HookBusFactory provides static methods:

Method Best suited for
create() Full control over the Identifier and Locator.
createWithArray() Quick setup using an array of handlers.
createWithCallable() Dynamic handler resolution.
createWithContainer() Symfony service containers and Dependency Injection.

HookBusFactory::create()

Argument Type Description
hookIdentifier HookIdentifierInterface The Identifier that will be used to locate the Handler.
handlerLocator HandlerLocatorInterface The Locator where the Handlers are registered.

Example

use RubenMartinDev\PrestashopModuleHookBus\HookBusFactory;
use RubenMartinDev\PrestashopModuleHookBus\Identifier\LiteralIdentifier;
use RubenMartinDev\PrestashopModuleHookBus\Locator\ArrayLocator;

$arrayLocator = new ArrayLocator();
$arrayLocator->addHandler('displayHeader', new DisplayHeaderHandler());

HookBusFactory::create(
    new LiteralIdentifier(),
    $arrayLocator
);

HookBusFactory::createWithArray()

Argument Type Description
hookIdentifier HookIdentifierInterface The Identifier that will be used to locate the Handler.
handlers array An array with key representing the Identifier and value the Handler. If the handler implements NamedHandlerInterface, key is optional.

Example

use RubenMartinDev\PrestashopModuleHookBus\HookBusFactory;
use RubenMartinDev\PrestashopModuleHookBus\Identifier\LiteralIdentifier;

HookBusFactory::createWithArray(
    new LiteralIdentifier(),
    ['displayHeader' => new DisplayHeaderHandler()]
);

HookBusFactory::createWithCallable()

Argument Type Description
hookIdentifier HookIdentifierInterface The Identifier that will be used to locate the Handler.
callable callable A callback that will resolve which Handler will be used.

Example

use RubenMartinDev\PrestashopModuleHookBus\HookBusFactory;
use RubenMartinDev\PrestashopModuleHookBus\Identifier\LiteralIdentifier;

HookBusFactory::createWithCallable(
    new LiteralIdentifier(),
    function ($identifier) {
        if ('displayHeader' === $identifier) {
            return new DisplayHeaderHandler();
        }
    }
);

HookBusFactory::createWithContainer()

Argument Type Description
container ContainerInterface Container where services are registered.
hookIdentifier HookIdentifierInterface The Identifier that will be used to locate the Handler.
handlers array An array with key representing the Identifier and value the service to use as Handler. If the handler implements NamedHandlerInterface, key is optional.

Example

Note

Service container integration requires PrestaShop 1.7 or higher, as PrestaShop 1.6 does not use Symfony, or, use your own container, for example prestashop/module-lib-service-container.

use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
use RubenMartinDev\PrestashopModuleHookBus\HookBusFactory;
use RubenMartinDev\PrestashopModuleHookBus\Identifier\LiteralIdentifier;

$container = SymfonyContainer::getInstance();

HookBusFactory::createWithContainer(
    $container,
    new LiteralIdentifier(),
    ['displayHeader' => 'my_module.hook.handler.display_header']
);

Identifier

Used to identify the hook and to locate the corresponding Handler during the dispatch cycle.

If the Identifier cannot resolve the identity, it will throw the exception UnresolvedHookIdentifierException.

Literal

The provided string will be used literally as the identifier.

Example

use RubenMartinDev\PrestashopModuleHookBus\HookBusFactory;
use RubenMartinDev\PrestashopModuleHookBus\Identifier\LiteralIdentifier;

class MyModule extends Module
{
    public function __construct()
    {
        // ...

        $this->hookBus = HookBusFactory::createWithArray(
            new LiteralIdentifier(),
            // ...
        );
    }

    public function hookDisplayHeader(array $params)
    {
        return $this->hookBus->dispatch('myCustomIdentity', $params);
    }
}

Method Hook

Designed to be used inside the module's public hook<hook_name>() methods. It obtains the identifier from the method name; for example, the method hookActionAdminControllerSetMedia() will be the identifier actionAdminControllerSetMedia.

Example

use RubenMartinDev\PrestashopModuleHookBus\HookBusFactory;
use RubenMartinDev\PrestashopModuleHookBus\Identifier\MethodHookIdentifier;

class MyModule extends Module
{
    public function __construct()
    {
        // ...

        $this->hookBus = HookBusFactory::createWithArray(
            new MethodHookIdentifier(),
            // ...
        );
    }

    public function hookDisplayHeader(array $params)
    {
        return $this->hookBus->dispatch(__FUNCTION__, $params);
    }
}

Callable

Through a callback we can generate a custom identifier.

Example

use RubenMartinDev\PrestashopModuleHookBus\HookBusFactory;
use RubenMartinDev\PrestashopModuleHookBus\Identifier\CallableIdentifier;

class MyModule extends Module
{
    public function __construct()
    {
        // ...

        $this->hookBus = HookBusFactory::createWithArray(
            new CallableIdentifier(function ($hookName) {
                if ('myCustomIdentity' === $hookName) {
                    return 'myCustomIdentityHandler';
                }
            }),
            // ...
        );
    }

    public function hookDisplayHeader(array $params)
    {
        return $this->hookBus->dispatch('myCustomIdentity', $params);
    }
}

Custom Identifier

You can create your own Identifiers to generate custom identities. It should implement the interface HookIdentifierInterface.

Example

use RubenMartinDev\PrestashopModuleHookBus\Identifier\HookIdentifierInterface;

final class MyCustomIdentifier implements HookIdentifierInterface
{
    public function identify($hookName)
    {
        return \strtolower($hookName);
    }
}

Locator

Where Handlers are located and which identities are associated with them.

If the Locator cannot resolve which Handler is assigned to the identity, it will throw the exception MissingHandlerException.

Array

Example

use RubenMartinDev\PrestashopModuleHookBus\Locator\ArrayLocator;

$locator = new ArrayLocator();

$locator->addHandler('displayHeader', new DisplayHeaderHandler());
$locator->addHandler('displayFooter', new DisplayFooterHandler());

Callable

Example

use RubenMartinDev\PrestashopModuleHookBus\Locator\CallableLocator;

$locator = new CallableLocator(function ($hookName) {
    if ('displayHeader' === $hookName) {
        return new DisplayHeaderHandler();
    }

    if ('displayFooter' === $hookName) {
        return new DisplayFooterHandler();
    }

    return null;
});

Container

Example

use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
use RubenMartinDev\PrestashopModuleHookBus\Locator\ContainerLocator;

$container = SymfonyContainer::getInstance();

$locator = new ContainerLocator($container);

$locator->addHandler('displayHeader', 'my_module.hook.handler.display_header');
$locator->addHandler('displayFooter', 'my_module.hook.handler.display_footer');

Custom Locator

You can create your own Locators that return which Handler will manage the hook. It should implement the interface HandlerLocatorInterface.

If you want it to be compatible with the Factory, you should implement the interface AppendableHandlerLocatorInterface to enable the addHandler() method.

Example

use RubenMartinDev\PrestashopModuleHookBus\Locator\HandlerLocatorInterface;

final class MyCustomLocator implements HandlerLocatorInterface
{
    public function getHandlerForIdentity($identity)
    {
        if ('displayHeader' === $identity) {
            return new DisplayHeaderHandler();
        }

        if ('displayFooter' === $identity) {
            return new DisplayFooterHandler();
        }

        throw MissingHandlerException::forIdentity($identity);
    }
}

Handler

Handlers are responsible for resolving what to do with the hook. They must implement the interface HookHandlerInterface.

The handle() method receives the $params argument, which is the same argument that the native hook<hook_name>() method of the module received.

If the Handler implements the interface NamedHandlerInterface, the Factory can infer the identity automatically from the static method getIdentityName().

Example

use RubenMartinDev\PrestashopModuleHookBus\Handler\NamedHandlerInterface;

final class DisplayHeaderHandler implements NamedHandlerInterface
{
    public static function getIdentityName()
    {
        return 'displayHeader';
    }

    public function handle(array $params = [])
    {
        $cartTotal = $params['cart']->getOrderTotal();

        return Tools::displayPrice($cartTotal);
    }
}

Exceptions

All library exceptions extend HookBusException.

Exception Description
MissingHandlerException No Handler was found for the resolved identity.
UnresolvedHookIdentifierException The Identifier could not resolve an identity.