phata / hook
A minimalistic hook library based on PHP's Interface feature and PSR-11 container.
Requires
- php: >=7.1
- psr/container: ^1.0
Requires (Dev)
Suggests
- php-di/php-di: PSR-11 Container implementation that with dependency injection and autowiring
This package is auto-updated.
Last update: 2024-10-27 10:26:24 UTC
README
A minimalistic hook library based on PHP's Interface feature and PSR-11 container.
Why
Many CMS (like Drupal, Wordpress) are based on hook system for their modules. They usually work like this:
- The CMS declare the hooks somewhere in their documentations.
- And provide a way for modules to declare that they implemented any hook.
- The modules implement the hook(s) as documented.
- Somewhere in the CMS, when the hook is "invoked", all implementations from (3) are drawn out and run against certain data. Returned values are collected.
They usually also allow modules to declare their own hook. But they need to implement (4) on their own. CMS would provide helper API for invoking the hooks.
This library provide a way to do so in a modern manner.
Installation
The recommended method is using composer:
composer require "phata/hook"
Then you should be able to use it with composer's autoloading.
Example Usage
Basic invoker map and reduce
```php // path to composer's autoloader require_once '../vendor/autoload.php'; $container = new DI\Container; // or other PHP-11 compliant container $registry = new Phata\Hook\Registry; $invoker = new Phata\Hook\Invoker($registry, $container); // declare existing interfaces as hook. $registry->declareHooks([ App\MyInterface::class, SomeAwesomeLibrary\Interface::class, ]); // add class to the registry, which would // automatically index against the declared // hooks. $registry->add([ App\MyModule1::class, App\MyModule2::class, FooBar\External\Module::class, ]); // use $invoker to invoke a hook // Use 1: map results $array = $invoker->map( App\MyInterface::class, function (App\MyInterface $module) { return $module->doSomething(); } ); // Use 2: reduce $result = $invoker->reduce( App\MyInterface::class, function ($carry, App\MyInterface $module) { return $module->process($carry); }, $someInitialValue ); ```Advanced Examples
Ordered modules with SortingInvoker
```php nameapace App; use Phata\Hook\SortableInterface; class MyModule1 implements SortableInterface, MyInterface { public function myProcess($input) { // some processsing of $input // ... return $output; } public function getWeight():int { // some logics to get the module's weight // perhapse from database operations // ... return $weight; } } ``` ```php // path to composer's autoloader require_once '../vendor/autoload.php'; $container = new DI\Container; // or other PHP-11 compliant container $registry = new Phata\Hook\Registry; $invoker = new Phata\Hook\SortingInvoker($registry, $container); // declare existing interfaces as hook. $registry->declareHooks([ Psr\Http\Server\MiddlewareInterface::class, ]); // add class to the registry, which would // automatically index against the declared // hooks. $registry->add([ App\MyModule1::class, App\MyModule2::class, FooBar\External\Module::class, ]); // handling the request // // Note: sorting invoker will sort the modules by their weight // before invoking. $results = $invoker->map( App\MyInterface::class, function (App\MyInterface $module) use ($input) { return $module->process($input); } ); // use the $results //... ```Consuming PSR-7 request with PSR-15 middleware
```php // path to composer's autoloader require_once '../vendor/autoload.php'; $container = new DI\Container; // or other PHP-11 compliant container $registry = new Phata\Hook\Registry; $invoker = new Phata\Hook\Invoker($registry, $container); // declare existing interfaces as hook. $registry->declareHooks([ Psr\Http\Server\MiddlewareInterface::class, ]); // add class to the registry, which would // automatically index against the declared // hooks. $registry->add([ App\MyModule1::class, App\MyModule2::class, FooBar\External\Module::class, ]); // handling the request $request = $invoker->reduce( Psr\Http\Server\MiddlewareInterface::class, function ($request, Psr\Http\Server\MiddlewareInterface::class $middleware) { return $middleware->process($request); }, GuzzleHttp\Psr7\ServerRequest::fromGlobals() ); // handler handles the request //... ```Reduce PSR-7 Request with `$carry` aggregation
```php // path to composer's autoloader require_once '../vendor/autoload.php'; $container = new DI\Container; // or other PHP-11 compliant container $registry = new Phata\Hook\Registry; $invoker = new Phata\Hook\Invoker($registry, $container); // declare existing interfaces as hook. $registry->declareHooks([ App\Middleware\Interface::class, ]); // add class to the registry, which would // automatically index against the declared // hooks. $registry->add([ App\MyModule1::class, App\MyModule2::class, FooBar\External\Module::class, ]); // handling the request $request = GuzzleHttp\Psr7\ServerRequest::fromGlobals(); $result = $invoker->reduce( App\Middleware\Interface::class, function ($carry, App\Middleware\Interface::class $middleware) use ($request) { $middleware->process($carry, $request); return $carry; }, null ); ```Documentation
Class and type documentation of Phata\Hook can be found here.
License
Phata\Hook is distributed under the MIT License. You should have received a copy of the GNU Lesser General Public License along with Phata/Hook. If not, see https://opensource.org/licenses/MIT.