2017 © Pedro Peláez
 

library stack

The Psr-15 middleware stack component of the ellipse framework

image

ellipse/stack

The Psr-15 middleware stack component of the ellipse framework

  • Wednesday, September 27, 2017
  • by pmall
  • Repository
  • 1 Watchers
  • 0 Stars
  • 104 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 1 Versions
  • 0 % Grown

The README.md

Dispatcher

This package provides a Psr-15 dispatcher implementation., (*1)

Require php >= 7.0, (*2)

Installation composer require ellipse/dispatcher, (*3)

Run tests ./vendor/bin/kahlan, (*4)

Using a dispatcher

This package provides an Ellipse\Dispatcher class allowing to process a Psr-7 request through a Psr-15 middleware queue (First in first out order) before handling it with a Psr-15 request handler in order to create a Psr-7 response., (*5)

It is basically a request handler decorator wrapping a middleware queue around a request handler. Its constructor takes two parameters:, (*6)

  • a request handler object implementing Psr\Http\Server\RequestHandlerInterface
  • an array containing middleware objects implementing Psr\Http\Server\MiddlewareInterface

The Dispatcher itself implements RequestHandlerInterface so a response is produced by using its ->handle() method with a request. It also means it can be used as the request handler of another Dispatcher. Also, The same Dispatcher can be used multiple times to handle as many requests as needed., (*7)

Finally when a value of the given middleware queue is not an implementation of MiddlewareInterface an Ellipse\Dispatcher\Exceptions\MiddlewareTypeException is thrown. Factory decorators can be used to resolve some type of values as middleware., (*8)

<?php

namespace App;

use Ellipse\Dispatcher;

// Create a dispatcher using two middleware and a request handler.
$dispatcher = new Dispatcher(new SomeRequestHandler, [
    new SomeMiddleware1,
    new SomeMiddleware2,
]);

// Here the request goes through SomeMiddleware1, SomeMiddleware2 and SomeRequestHandler.
$response = $dispatcher->handle($request);

// It can be used as the request handler of another dispatcher.
// Here the request goes through SomeMiddleware3, SomeMiddleware1, SomeMiddleware2 and SomeRequestHandler
(new Dispatcher($dispatcher, [new SomeMiddleware3]))->handle($request);

// Here a MiddlewareTypeException is thrown because 'something' is not a Psr-15 middleware.
new Dispatcher(new SomeRequestHandler, [new SomeMiddleware, 'something']);

The Dispatcher class also has a ->with() method taking a MiddlewareInterface as parameter. It returns a new dispatcher with the given middleware wrapped around the current dispatcher. The new middleware will be the first processed by the new dispatcher:, (*9)

<?php

namespace App;

use Ellipse\Dispatcher;

// Create a dispatcher with two middleware.
$dispatcher = new Dispatcher(new SomeRequestHandler, [
    new SomeMiddleware1,
    new SomeMiddleware2,
]);

// Create a new dispatcher with a new middleware on the top of the middleware queue.
$dispatcher = $dispatcher->with(new SomeMiddleware3);

// Here the request goes through SomeMiddleware3, SomeMiddleware1, SomeMiddleware2 and SomeRequestHandler.
$response = $dispatcher->handle($request);

// It allows to create dispatchers from the outside-in if you like.
$dispatcher = new Dispatcher(new SomeRequestHandler);

$dispatcher = $dispatcher->with(new SomeMiddleware3);
$dispatcher = $dispatcher->with(new SomeMiddleware2);
$dispatcher = $dispatcher->with(new SomeMiddleware1);

// Here the request goes through SomeMiddleware1, SomeMiddleware2, SomeMiddleware3 and SomeRequestHandler.
$response = $dispatcher->handle($request);

Middleware and request handler resolving

A common practice is to allow callables and class names registered in a container to be used as regular middleware/request handler., (*10)

For this purpose this package also provides an Ellipse\DispatcherFactory class implementing Ellipse\DispatcherFactoryInterface, allowing to produce Dispatcher instances. Its __invoke() method takes any value as request handler and an optional middleware queue. An Ellipse\Dispatcher\Exceptions\RequestHandlerTypeException is thrown when the given request handler is not an implementation of RequestHandlerInterface., (*11)

<?php

namespace App;

use Ellipse\DispatcherFactory;

// Get a dispatcher factory.
$factory = new DispatcherFactory;

// Use the factory to create a new Dispatcher.
$dispatcher = $factory(new SomeRequestHandler, [new SomeMiddleware]);

// Here a RequestHandlerTypeException is thrown because 'something' is not a Psr-15 request handler.
$dispatcher = $factory('something', [new SomeMiddleware]);

// Here a MiddlewareTypeException is thrown by the Dispatcher class because 'something' is not a Psr-15 middleware.
$dispatcher = $factory(new SomeRequestHandler, [new SomeMiddleware, 'something']);

This class is not very useful by itself. The point of DispatcherFactory is to be decorated by other factories resolving the given values as Psr-15 implementations before delegating it the dispatcher creation. It is a starting point for such factory decorators (also called resolvers) which ensure the dispatcher creation fails nicely when any value is not resolved as a Psr-15 implementation by any decorator., (*12)

Here is an example of callable resolving using the Ellipse\Dispatcher\CallableResolver class from the ellipse/dispatcher-callable package:, (*13)

<?php

namespace App;

use Ellipse\DispatcherFactory;
use Ellipse\Dispatcher\CallableResolver;

// Get a decorated dispatcher factory.
$factory = new CallableResolver(new DispatcherFactory);

// A dispatcher using both callables and Psr-15 implementations can now be created.
$middleware = function ($request, $handler) {

    // This callable behave like a Psr-15 middleware.

};

$handler = function ($request) {

    // This callable behave like a Psr-15 request handler.

};

// This works.
$response = $factory($handler, [$middleware, new SomeMiddleware])->handle($request);

Here is some ellipse packages providing resolvers for common resolving scenario:, (*14)

Here is an example of a class implementing DispatcherFactoryInterface in case you need to create a custom one:, (*15)

<?php

namespace App;

use Ellipse\Dispatcher;
use Ellipse\DispatcherFactoryInterface;

class MyResolver implements DispatcherFactoryInterface
{
    private $delegate;

    public function __construct(DispatcherFactoryInterface $delegate)
    {
        $this->delegate = $delegate;
    }

    public function __invoke($handler, array $middleware = []): Dispatcher
    {
        // Replace the handler with a ResolvedRequestHandler when the request handler should be resolved.
        $handler = $this->shouldResolveHandler($handler)
            : new ResolvedRequestHandler($handler)
            ? $handler;

        // Replace middleware with a ResolvedMiddleware when a middleware should be resolved.
        $middleware = array_map(function ($middleware) {

            return $this->shouldResolveMiddleware($middleware)
                ? new ResolvedMiddleware($middleware)
                : $middleware;

        }, $middleware);

        // Delegate the dispatcher creation to the decorated factory.
        return ($this->delegate)($handler, $middleware);
    }

    private shouldResolveHandler($handler): bool
    {
        // ...
    }

    private shouldResolveMiddleware($middleware): bool
    {
        // ...
    }
}

The Versions

27/09 2017

dev-master

9999999-dev https://github.com/ellipsephp/stack

The Psr-15 middleware stack component of the ellipse framework

  Sources   Download

MIT

The Requires

 

The Development Requires

by Pierre Mallinjoud

middleware stack psr-15