src/MiddlewareAwareTrait.php
<?php
/**
* Middleware trait, heavily influenced by Slim PHP's awesomeness.
*/
namespace AvalancheDevelopment\Talus;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use RuntimeException;
use UnexpectedValueException;
trait MiddlewareAwareTrait
{
/** @var array */
protected $stack = [];
abstract public function __invoke(RequestInterface $request, ResponseInterface $response);
/**
* @param callable $callable
* @return integer
*/
public function addMiddleware(callable $callable)
{
if (empty($this->stack)) {
// todo not sure if i like seeding the stack like this...
$this->seedStack($this);
}
$decoratedMiddleware = $this->decorateMiddleware($callable);
return array_unshift($this->stack, $decoratedMiddleware);
}
/**
* @param callable $callable
* @return callable
*/
protected function decorateMiddleware(callable $callable)
{
$next = reset($this->stack);
return function (RequestInterface $request, ResponseInterface $response) use ($callable, $next) {
$result = call_user_func($callable, $request, $response, $next);
if (!($result instanceof ResponseInterface)) {
throw new UnexpectedValueException('Middleware must return instance of Psr Response');
}
return $result;
};
}
/**
* @param callable $callable
* @return integer
*/
protected function seedStack(callable $callable)
{
if (!empty($this->stack)) {
throw new RuntimeException('Can only seed the stack once');
}
$this->stack = [];
return array_push($this->stack, $callable);
}
/**
* @param RequestInterface $request
* @param ResponseInterface $response
* @return RequestInterface
*/
public function callStack(RequestInterface $request, ResponseInterface $response)
{
if (empty($this->stack)) {
$this->seedStack($this);
}
$top = reset($this->stack);
return $top($request, $response);
}
}