phapi/pipeline

View on GitHub
readme.md

Summary

Maintainability
Test Coverage
# Phapi Middleware Pipeline

[![Build status](https://img.shields.io/travis/phapi/pipeline.svg?style=flat-square)](https://travis-ci.org/phapi/pipeline)
[![Code Climate](https://img.shields.io/codeclimate/github/phapi/pipeline.svg?style=flat-square)](https://codeclimate.com/github/phapi/pipeline)
[![Test Coverage](https://img.shields.io/codeclimate/coverage/github/phapi/pipeline.svg?style=flat-square)](https://codeclimate.com/github/phapi/pipeline/coverage)

Phapi relies heavily on middleware. Almost everything is a middleware: routing, content negotiation and many other things.

## Why middleware?
The benefits are many. Middleware are easy to replace and from a performance perspective they can, if implemented right, bypass a lot of code that doesn't need to run in specific circumstances, for example, if a client hits their rate limit there is no point in executing routing, dispatching etc.

## Installation
The package is installed by default by the Phapi framework. Installing the package to use is separately can be done by using composer:

```shell
$ composer require phapi/pipeline:1.*
```

## Usage
Attaching a new middleware to the pipeline are done by using the <code>pipe()</code> method.

```php
<?php
$pipeline = new Phapi\Middleware\Pipeline();
$pipeline->pipe(new Middleware\Cors());
```

Please note that middleware's will be called in the order they are attached.

A middleware CAN implement the Middleware Interface, but MUST be callable. All middleware WILL be called with three parameters: Request, Response and Next. A middleware should invoke the <code>$next</code> variable and pass the <code>$request</code>, <code>$response</code> and <code>$next</code> parameters. A middleware must also return a response.

Once the queue is empty the resulted response instance will be returned.

## Error handling
Implementing the ErrorMiddleware interface enables the pipeline to be able to handle errors. The middleware must take care of the error handling and call the <code>prepareErrorQueue()</code> method. This will trigger a reset in the pipeline and only the middleware added before (usually serializer middleware and a middleware sending the response to the client) the ErrorMiddleware will be called.


## Create your own middleware class

Middleware requires a request and a response and a callback (<code>$next</code>) that is called if the middleware allows further middleware to process the request. If a middleware doesn't need or desire to allow further processing it should not call the callback (<code>$next</code>) and should instead return a response. Note that <code>$next</code> can be <code>null</code>.

The main task of a middleware is to process an incoming request and/or the response. The middleware must accept a request and a response (PSR-7 compatible) instance and do something with them.

The middleware must pass a request and a response to the ($next) callback and finally either return the response from the ($next) callback or by modifying the response before returning it.

**Examples:**
```php
<?php
  public function __invoke(
    Request $request,
    Response $response,
    callable $next)
  {
      // Do something ...

      return $next($request, $response, $next);
  }
```

**OR**

```php
<?php
  public function __invoke(
    Request $request,
    Response $response,
    callable $next)
  {
      // Do something ...

      $response = $next($request, $response, $next);

      // Modify response ...

      return $response;
  }
```

If the middleware should break the pipeline, example: the client hit the rate limit, it should return a response instead of invoking <code>$next</code>.

**Example:**

```php
<?php
  public function __invoke(
    Request $request,
    Response $response,
    callable $next)
  {
      if ($this->tooManyRequests()) {
        // Set appropriate headers and body

        // Return response
        return $response;
      }

      return $next($request, $response, $next);
  }
```

### Dependency Injection Container
If you implement a method named <code>setContainer()</code> the pipeline will call that method and provide the Dependency Injector Container that can be used in the <code>__invoke()</code> method.

**Example:**

```php
<?php
  public function setContainer($container)
  {
    $this->container = $container;
  }
```

### Complete example
Here is a complete example of how a middleware should look. Use this example as a starting point when you wan't to write your own middleware.

```php
<?php

namespace Phapi\Middleware\Example;

use Phapi\Contract\Di\Container;
use Phapi\Contract\Middleware\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

/**
 * Eample middleware
 *
 * @category Phapi
 * @package  Phapi\Middleware\Example
 * @author   Peter Ahinko <peter@ahinko.se>
 * @license  MIT (http://opensource.org/licenses/MIT)
 * @link     https://github.com/phapi/middleware-example
 */
class Example implements Middleware
{

    /**
     * Dependency injection container
     *
     * @var Container
     */
    private $container;

    /**
     * Set dependency injection container
     *
     * @param Container $container
     */
    public function setContainer(Container $container)
    {
        $this->container = $container;
    }

    /**
     * Invoking the middleware
     *
     * @param ServerRequestInterface $request
     * @param ResponseInterface $response
     * @param callable $next
     * @return ResponseInterface $response
     */
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null)
    {
        // Do something ...

        // Call next middleware
        $response = $next($request, $response, $next);

        // Do something with the response ...

        // Return the response
        return $response;
    }
}

```

## License
Phapi Middleware Pipeline is licensed under the MIT License - see the [license.md](https://github.com/phapi/pipeline/blob/master/license.md) file for details

## Contribute
Contribution, bug fixes etc are [always welcome](https://github.com/phapi/pipeline/issues/new).