yiisoft/middleware-dispatcher

PSR-15 middleware dispatcher

5.2.0 2023-09-25 07:01 UTC

README

68747470733a2f2f796969736f66742e6769746875622e696f2f646f63732f696d616765732f7969695f6c6f676f2e737667

Yii Middleware Dispatcher


Latest Stable Version Total Downloads Build status Scrutinizer Code Quality Code Coverage Mutation testing badge static analysis type-coverage psalm-level

The package is a PSR-15 middleware dispatcher. Given a set of middleware and a request instance, dispatcher executes it and produces a response instance.

Requirements

  • PHP 8.1 or higher.

Installation

The package could be installed with composer:

composer require yiisoft/middleware-dispatcher

General usage

To use a dispatcher, you need to create it first:

use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
use Yiisoft\Middleware\Dispatcher\MiddlewareFactory;

$dispatcher = new MiddlewareDispatcher(
    new MiddlewareFactory($diContainer),
    $eventDispatcher
);

In the above $diContainer is an instance of PSR-11 \Psr\Container\ContainerInterface and $eventDispatcher is an instance of PSR-14 Psr\EventDispatcher\EventDispatcherInterface.

After dispatcher instance obtained, it should be fed with some middleware:

$dispatcher = $dispatcher->withMiddlewares([
    TeapotAccessChecker::class,
    static function (): ResponseInterface {
        return new Response(418);
    },
]);

In the above we have used a callback. Overall the following options are available:

  • A controller handler action in format [TestController::class, 'index']. TestController instance will be created and index() method will be executed.
  • A name of PSR-15 middleware class. The middleware instance will be obtained from container.
  • A name of PSR-15 request handler class. The request handler instance will be obtained from container and executed.
  • A name or instance of invokable class. If the name of invokable class is provided, the instance will be obtained from container and executed.
  • A function returning a middleware such as
    static function (): MiddlewareInterface {
        return new TestMiddleware();
    }
    The middleware returned will be executed.
  • A callback function(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface.
  • An array definition (see syntax) of middleware:
    [
        'class' => MyMiddleware::class,
        '__construct()' => [
            'someVar' => 42,
        ],
    ]

For handler action and callable typed parameters are automatically injected using dependency injection container. Current request and handler could be obtained by type-hinting for ServerRequestInterface and RequestHandlerInterface.

After middleware set is defined, you can do the dispatching:

$request = new ServerRequest('GET', '/teapot');
$response = $dispatcher->dispatch($request, $this->getRequestHandler());

Given a request dispatcher executes middleware in the set and produces response. First specified middleware will be executed first. For each middleware \Yiisoft\Middleware\Dispatcher\Event\BeforeMiddleware and \Yiisoft\Middleware\Dispatcher\Event\AfterMiddleware events are triggered.

Creating your own implementation of parameters resolver

Parameters resolver could be customized by providing your own ParametersResolverInterface implementation:

use \Psr\Http\Message\ServerRequestInterface;
use \Yiisoft\Middleware\Dispatcher\ParametersResolverInterface;

class CoolParametersResolver implements ParametersResolverInterface
{
    public function resolve(array $parameters, ServerRequestInterface $request): array
    {
        $resolvedParameters = [];
        foreach ($parameters as $name => $parameter) {
            if ($request->getAttribute($name) !== null) {
                $resolvedParameters[$name] = $request->getAttribute($name)
            }
        }
        
        return $resolvedParameters;
    }
}

Then it could be used like the following:

use Psr\Container\ContainerInterface;
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
use Yiisoft\Middleware\Dispatcher\MiddlewareFactory;
use Yiisoft\Middleware\Dispatcher\ParametersResolverInterface;

/** 
 * @var ContainerInterface $container
 * @var ParametersResolverInterface $resolver
 * @var EventDispatcherInterface $eventDispatcher 
 */
$dispatcher = new MiddlewareDispatcher(new MiddlewareFactory($container, $resolver), $eventDispatcher);

To combine several parameters' resolvers use CompositeParametersResolver:

use Psr\Container\ContainerInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Yiisoft\Middleware\Dispatcher\CompositeParametersResolver;
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
use Yiisoft\Middleware\Dispatcher\MiddlewareFactory;
use Yiisoft\Middleware\Dispatcher\ParametersResolverInterface;

/** 
 * @var ContainerInterface $container
 * @var ParametersResolverInterface $resolver1
 * @var ParametersResolverInterface $resolver2
 * @var EventDispatcherInterface $eventDispatcher 
 */
$dispatcher = new MiddlewareDispatcher(
    new MiddlewareFactory($container, new CompositeParametersResolver($resolver1, $resolver2)), 
    $eventDispatcher,
);

Testing

Unit testing

The package is tested with PHPUnit. To run tests:

./vendor/bin/phpunit

Mutation testing

The package tests are checked with Infection mutation framework with Infection Static Analysis Plugin. To run it:

./vendor/bin/roave-infection-static-analysis-plugin

Static analysis

The code is statically analyzed with Psalm. To run static analysis:

./vendor/bin/psalm

License

The Yii Middleware Dispatcher is free software. It is released under the terms of the BSD License. Please see LICENSE for more information.

Maintained by Yii Software.

Support the project

Open Collective

Follow updates

Official website Twitter Telegram Facebook Slack