Site icon Hip-Hop Website Design and Development

Darren Mothersele: How to do Everything with PHP Middleware (Cheap WordPress maintenance support plansCamp London)

At the WordPress maintenance support plansCamp in London earlier this month I gave a talk
about PHP Middleware.
You can see a recording of the talk
on YouTube. Here’s a summary, in case you don’t want to watch
the whole talk, or the distorted audio upsets you, or if you
want the links and references:

Simple vs Easy

I started with a reference to the important talk by Rich Hickey,
Simple Made Easy.
This is high up on my list of videos every software developer needs to watch.
I began here because I think it’s important to identify the difference
between simple and easy, to identify where complexity sneaks into our
systems. I have found PHP Middleware to be an important tool in
the fight against complexity.

“programming, when stripped of all its circumstantial irrelevancies, boils
down to no more and no less than very effective thinking so as to avoid
unmastered complexity, to very vigorous separation of your many different concerns.

– Edsgar W. Dijkstra (1930 – 2002)

De-complecting PHP

I talked a bit about different ways to simplify development with PHP.
Including: Domain-driven design, Hexagonal architecture (Ports and
Adapters), Framework-independent code, Thin APIs, etc…
In particular, I wanted to emphasise the importance of framework-independent
code and the benefit of using common interfaces such as the ones developed
as PSRs by PHP-FIG.

There was some discussion after about introducing unecessary abstractions,
but I think this misses the point. Of course there is a trade off, but the
key is to focus on the simplicity, on untwisting things (c.f. Rich Hickey).

De-coupled

Inspired by the Zend Expressive
installation procedure, I imagined what WordPress maintenance support plans 10 might look like, with
fully-decoupled components.

Interfaces

The widespread adoption of PSR7 by the PHP community has lead to the
popularity of PHP Middleware-based systems.

Why PSR7 when Symfony HTTP components were so popular?
Well, that is an implementation – and rather than standardise on
implementation, we should standardise against interfaces.

This allows more interoperability. I showed this pseudocode:

// Take the incoming request from Diactoros
$request = ServerRequestFactory::fromGlobals();

$client = new Client();

// Response comes back from Guzzle
$response = $client->send($request->withUrl($dest));

$body = simplexml_load_string(
$response->getBody()->getContents());

// pass back to Diactoros
(new SapiEmitter)->emit($response->withBody($body));

The example uses HTTP requests from
Zend Diactoros,
forwards them using the Guzzle
HTTP client, and returns the response object from Guzzle
using the SAPI Emitter from Diactoros.

This demonstrates the power of sharing standard interfaces.
Here two packages are used together, both provide
an implementation of PSR7 HTTP messages, and they
work seamlessly because they both conform to the same interface,
despite the differing implementation details.

Decorating Web Apps

This is what a typical web app looks like:

Which can be simplified to this:

A web app takes a request and returns a response.

The concept behind PHP Middleware is that you can decorate
the app, to add new functionality, by intercepting the request
on the way in, and the response on the way out.
This avoids the complexity of intertwining your code
throughout the ball of mud.

Here’s an example (pseudocode) for adding CORS
functionality to an existing app:

$cors = analyze($request);
switch ($cors->getRequestType()) {
Case ERR_NO_HOST_HEADER:
Case ERR_ORIGIN_NOT_ALLOWED:
Case ERR_METHOD_NOT_SUPPORTED:
Case ERR_HEADERS_NOT_SUPPORTED:
Return createResponse(403);

Case TYPE_REQUEST_OUT_OF_CORS_SCOPE:
return $APP->process($request);

Case TYPE_PRE_FLIGHT_REQUEST:
$response = UtilsFactory::createResponse(200);
Return $response->withHeaders($cors->getHeaders);

default:
$response = $APP->process($request);
Return $response->withHeaders($cors->getHeaders);
}

StackPHP first popularised the concept of middleware
in PHP. This diagram is from their website:

There are other popular micro-frameworks based on this concept,
such as Slim.

The core of your app is just a thin layer of business logic.
Just your domain specific code. The rest can be wrapped in layers
which isolate and separate concerns nicely.

Single-pass vs Double-pass

The double pass approach became the most popularly used
signature for HTTP middleware, based on
Express middleware
from the JS community.

It looks like this:

// DOUBLE PASS
function __invoke($request, $response, $next) {
}

The request and the response are both passed into the middleware,
along with a $next delegate that is called to pass
control and carry on processing down the chain of middleware.

This double-pass approach is much newer, but
used by most of the early adopters of PSR-7.

A single pass approach, looks like this:

// SINGLE PASS / LAMBDA
function process($request, $delegate) {
}

The issue is with how the response object is dealt with.
In the double-pass approach, both are provided.
The argument is that this is better for dependency
inversion. Using the single pass approach you either
need to hard code a dependency on a HTTP message
implementation into your middleware when the response
is required, or you need to inject a factory for
generating the response.

PSR-15 HTTP Middleware

After the success of PSR7, with it’s wide adoption leading to
much standardisation and interoperability in PHP frameworks,
the next step is to standardise the middleware interface.

This is not yet an accepted PSR. At the time of writing
it is still in draft status.
It is available for use in the
http-interop/http-middleware repo.

Invoker

As an aside, I mentioned the Invoker Interface.
As per the docs:

“Who doesn’t need an over-engineered call_user_func()?”

In particular this library really simplifies the process
of calling things and injecting dependencies.
It also allows to call things using named parameters.
I make extensive use of this, and I find making calls with
named parameters makes code much easier to understand.

PSR-15 Interfaces

PSR-15 has two interfaces. Both define a method called process.
One is the signature that middleware must support, which takes
a PSR7 request and a PSR15 delegate. The other interface defines
the process method for the delegate. The method on both
interfaces is defined as returning a PSR7 response.

So you can compose a chain of middleware, pass in a request
and get a response. The request is passed down the chain of
middleware until a response is generated which is then passed
back up the chain, possibly being decorated along the way.

For want of a better name, I refer to this chain of middleware
as a stack. And, I have created a simple
Stack Runner to
handle the processing of a stack of PSR-15 middleware.

class StackRunner implements DelegateInterface
{
public function __construct(
array $stack,
InvokerInterface $invoker,
ResponseFactoryInterface $responseFactory
) { … }

public function process(ServerRequestInterface $request)
{
if (!isset($this->stack[$this->current])) {
return $this->responseFactory->createResponse();
}
$middleware = $this->stack[$this->current];
$this->current++;

return $this->invoker->call([$middleware, ‘process’], [
‘request’ => $request,
‘delegate’ => $this,
]);
}
}

ADR (Action Domain Responder)

I went on to talk about ADR as being an adaptation of MVC that
is more suitable for use in Web Apps.
I’ve found this particularly useful when using Domain-Driven Design,
or when used to create thin APIs where you
have just a thin layer of business logic on top of a data store.

The issue with MVC is that the template is not the view.
The “view” of a web app is the HTTP response, and we split this
across our layers, as the body of the response is typically generated
by the view, with the knowledge of HTTP being encoded into our controllers.
We also bundle together various actions into one controller, which
means instantiating the whole thing when we want to run one of the actions.

ADR offers an alternative separation of concerns, where the
action methods of the controller are their own separate classes
(or in my case anything invokable via the InvokerInterface).
I use an InputHandler to deal with parsing the input from the HTTP Request,
which the Invoker can then use (via the magic of named arguments).

The domain (Model in MVC terminology) is where the business logic lives.
This is called domain, rather than model, to suggest use of
domain-driven design.

To use ADR with PHP Middleware, add a resolver to the end of the
chain of middleware to dispatch the request to the appropriate
Action.

Action

I’ve created a reference implementation of an invokable
Action.

Demo!

At this point in my talk I planned to give a demo of
how you compose ADR with Middleware to create a working API.
Unfortunately, I had some tech issues getting my computer linked
up to the projector, and I was starting to feel really ill (full of
cold). By this time the caffeine was starting to wear off, and
I needed the talk to end!

I’ve put the example code up in a
GitHub repo.

References

Simple Made Easy – talk by Rich Hickey
HTTP Middleware and
HTTP Factory interfaces.
PSR15 Middlewares a
set of really useful middlewares that can be used with a PSR15 middleware
dispatcher.
Stack Runner
my reference implementation of a very simple stack runner for executing
a chain of PSR15 middleware.
Wafer an experimental implementation
of the ADR idea to be used along with PSR15 middleware and the stack runner.

Drop me a line with any feedback. Thanks!
Source: New feed