Published February 12, 2015 By Richard Bagshaw - Edit page on Github

Written by Richard Bagshaw a php, javascript, vue and react freelancer who lives and works in Nottingham, UK. Follow me on Twitter

Middleware isn’t something that exclusive to any particular framework and it has in fact been around for a long time.

As a freelancer I frequently get to work on really interesting stuff, and recently I have been building a super lightweight custom framework based on illuminate components, one of the requirements was to build in an easy to use middleware component based on StackPHP

The Decorator Pattern

Before we can really talk about middleware and StackPHP we need to understand the decorator pattern, there have been many articles regarding this pattern over the years so I won’t try and concoct anything new here, instead I will be like so many others before me and quote wikipedia.

The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new decorator class that wraps the original class. This pattern is designed so that multiple decorators can be stacked on top of each other, each time adding a new functionality to the overridden method(s).

So the idea is basically this, you take an object, and you wrap this object in another object which provides additional functionality, and you keep wrapping extra classes repeatedly for each additional requirement.

As an example, we could take a web application and wrap that using the decorator pattern with another class that provides logging, we could then wrap this again with another class that provides caching, on so on.

This is basically achieved by implementing an interface on your original class, and then having each decorator class implement that same interface, because of this we can then safely wrap either our object or a previously decorated object and be confident that it will react in the same way.

Stack PHP

So armed with the knowledge of the decorator pattern, we can now talk about StackPHP, they say a picture is worth a thousand words, so with that in mind.

Looking at this we can easily see that in the center we have our application which will implement some common interface, and around it we can see additional middleware layers for Authentication and Session , both of these will also implement this common interface.

As our request / response travels through our application we can modify or alter behaviour as necessary.

At this point you may be thinking about this interface? for this to work surely we would need a common interface that is almost an industry standard? .. right?

HttpKernelInterface

HttpKernelInterface is just that, its single responsibility is to handle a request and convert this into some kind of response , that’s it, nothing more.

If we take a look at the code for this you will see how simple this interface really is.

<?php namespace Symfony \ Component \ HttpKernel ; use Symfony \ Component \ HttpFoundation \ Request ; use Symfony \ Component \ HttpFoundation \ Response ; interface HttpKernelInterface { const MASTER_REQUEST = 1 ; const SUB_REQUEST = 2 ; public function handle ( Request $request , $type = self : : MASTER_REQUEST , $catch = true ) ; }

As you can see, this ensures that we implement a method called handle() that receives a Request and returns a Response object.

So with this interface we simply make sure our main application class (IoC container) implements this interface, and any additional middleware we develop should also implement this.

Quick Example

$app = new Cartisan \ Core \ App ; $app - > get ( '/' , function ( ) { return 'Hello World!' ; } ) ; $app = new Cartisan \ Middleware \ Logger ( $app ) ;

In the above example we are creating a new instance of Cartisan\Core\App , adding a route and then finally creating a new instance of our middleware and passing in the core application, therefore “wrapping” it.

The middleware in this example could look something like this.

namespace Cartisan \ Middleware ; use Cartisan \ Core \ App ; use Symfony \ Component \ HttpFoundation \ Request ; use Symfony \ Component \ HttpKernel \ HttpKernelInterface ; class Logger implements HttpKernelInterface { protected $app ; public function __construct ( HttpKernelInterface $app ) { $this - > app = $app ; } public function handle ( Request $request , $type = self : : MASTER_REQUEST , $catch = true ) { return $this - > app - > handle ( $request ) ; } }

A few important points to notice here.

We must implement the HttpKernelInterface this makes sure that we have a handle() method available on all middleware. When we instantiate this class, we need to make sure that we pass in $app , this can be either the original $app or a previously decorated one, it doesn’t matter as we are type hinting the interface in the constructor, as long as it implements that interface, then we accept it as an argument.

At this point the rest is simple, as a request passes through our application it first goes through the handle() method for the middleware, which then in turn calls the handle() method on the next layer, and the next and so on.

Awesome!! .. right?!

Stack/Builder

So in the previous example we decorated our app with a really simple logger, but in the real world (as you know) it’s not always that simple, we may also pass in additional options when using the decorator, essentially it can start to look more like this.

use Symfony \ Component \ HttpKernel \ HttpCache \ Store ; use Symfony \ Component \ HttpKernel \ HttpCache \ HttpCache ; $app = new Silex \ Application ( ) ; $app - > get ( '/' , function ( ) { return 'Hello World!' ; } ) ; $app = new Stack \ Session ( new HttpCache ( $app , new Store ( __DIR__ . '/cache' ) ) ) ;

Whilst this is not the most verbose thing in the world, it’s ugly and I have to think when I look at this. StackPHP also offers some neat tools, one of them being Stack/Builder

Using Stack/Builder converts the code above into something like this.

$stack = ( new Stack \ Builder ( ) ) - > push ( 'Stack\Session' ) - > push ( 'Symfony\Component\HttpKernel\HttpCache\HttpCache' , new Store ( __DIR__ . '/cache' ) ) ; $app = $stack - > resolve ( $app ) ;

Some would argue that this is not much cleaner, but you can take this one step further by creating a helper to iterate over an array of middleware and push them onto the stack.

$stack = $app - > middleware ( [ 'Stack\Session' , 'Symfony\Component\HttpKernel\HttpCache\HttpCache' ] ) ; $app = $stack - > resolve ( $app ) ;

You COULD go even further by abstracting the array out into a config file, but I think you understand my point here.

Conclusion