Skip to content

Instantly share code, notes, and snippets.

@mindplay-dk
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mindplay-dk/aac76b50c30e36a9eabc to your computer and use it in GitHub Desktop.
Save mindplay-dk/aac76b50c30e36a9eabc to your computer and use it in GitHub Desktop.
Draft filter interface for standardization of message exchange
<?php
// Sample implementation of a FilterInterface apadater for Conduit (UNTESTED)
use Phly\Conduit\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\FilterInterface as Filter;
class ConduitFilterAdapter implements MiddlewareInterface
{
/**
* @var \Psr\Http\Message\FilterInterface
*/
private $filter;
/**
* @param \Psr\Http\Message\FilterInterface $filter
*/
public function __construct(Filter $filter)
{
$this->filter = $filter;
}
/**
* {@inheritdoc}
*/
public function __invoke(Request $request, Response $response, callable $next = null)
{
if ($this->filter->applyFilter($request, $response)) {
return $next($request, $response);
} else {
return $response;
}
}
}
<?php
namespace Psr\Http\Message;
/**
* Representation of a filter being applied to a request/response pair
* while processing an HTTP request.
*
* Each filter decides autonomously whether or not to delegate control
* to the the next filter instance in the chain - it returns TRUE or FALSE
* indicating whether or not to continue with the next filter.
*
* Note that both $request and $response are passed by reference - the
* objects themselves are immutable, but $request and $response work both
* as arguments and (optionally) as return values providing request/response
* arguments for the next filter.
*/
interface FilterInterface
{
/**
* @param ServerRequestInterface &$request the request being processed
* @param ResponseInterface &$response the response being generated
*
* @return bool true to continue; false to stop processing the filter chain
*/
public function applyFilter(ServerRequestInterface &$request, ResponseInterface &$response);
}
<?php
/**
* Reference middleware stack implementation.
*/
class Stack
{
/**
* @var FilterInterface[]
*/
private $filters = array();
/**
* @param FilterInterface $filter
*
* @return void
*/
public function addFilter(FilterInterface $filter)
{
$this->filters[] = $filter;
}
/**
* @param ServerRequestInterface $request
*
* @return ResponseInterface|null
*/
public function dispatch(ServerRequestInterface $request)
{
$response = null;
for ($i=0; $i<count($this->filters); $i++) {
$filter = $this->filters[$i];
$result = $filter->applyFilter($request, $response);
if ($result === false) {
break; // abort after last filter
}
}
return $response;
}
}
// EXAMPLE:
$test = new Stack();
$test->addFilter(new FooFilter);
$test->addFilter(new BarFilter);
$response = $test->dispatch();
@mindplay-dk
Copy link
Author

I feel strongly that something like an HttpFilter interface ought to be included as part of PSR-7. Having a defined interface for the request/response exchange cycle, to me, is as natural as having the request and response interfaces themselves - in fact, the exchange of request and response are the only thing that makes a request or response abstraction useful or interesting in the first place.

Conceptually, request and response are two parts of a whole - neither is interesting when taken out of context from the other, yet, currently, there is nothing in the PSR establishing any kind of relationship between them.

It should be fairly easy for various middleware stacks (such as Symfony, Slim, Silex, Stack, Conduit and Laravel) to implement simple adapters to support the proposed interface - reducing the community workload from one adapter for every filter for every framework, to a single filter interface adapter per framework.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment