rubenmartindev / prestashop-module-hook-bus
Flexible and centralized way to route and handle PrestaShop hooks
Package info
github.com/rubenmartindev/prestashop-module-hook-bus
pkg:composer/rubenmartindev/prestashop-module-hook-bus
Requires
- php: >=5.6.0
Requires (Dev)
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. |