PSR7 Bridge for CakePHP

I’m excited to announce the availability of a PSR7 Bridge plugin for CakePHP. This plugin lets you bridge PSR7 Middleware with CakePHP 3.3+ applications.

What is PSR7?

PSR7 is a recent recommendation from the PHP-FIG group (of which CakePHP is a member). It describes a set of interfaces for requests and responses. When implemented these interfaces allow the creation and consumption of framework agnostic request & response handling code. As an application developer PSR7 interests me because it enables me to more easily leverage tools built outside the CakePHP community. As a maintainer of CakePHP PSR7 interests me as I can maintain less code and users new to CakePHP have less to learn if they’ve used other PSR7 projects before. If you’ve ever used Rack in Ruby, or WSGI in Python, that is the general intent of PSR7 as well.

How the Plugin Works

Because PSR7 is a community standard, there are several existing implementations. I didn’t feel that re-implementing the PSR7 interfaces would provide any value so I opted to use an existing implementation. After evaluating a few different libraries, I chose to use zend-diactoros because the team at ZF produces well built, well tested libraries. The cakephp-spekkoek plugin is unlike most plugins you have used in the past. Because it needs to replace the low-level HTTP layers of CakePHP, it requires a slightly more invasive installation and setup. Installation is done with composer:

There are a few notable differences between this entry-point script and the one CakePHP comes with:

We aren’t loading our config/bootstrap.php file. Instead we’re using an Application class. We’ll cover this more in a bit.

We aren’t using the CakePHP Request, Response or Dispatcher classes. Instead we’re using Server class from Spekkoek. The Server class knows how to dispatch PSR7 requests and emit PSR7 responses to the webserver.

As mentioned earlier, a critical part of the new dispatch process is the Application. The Application class defines the following:

It ‘bootstraps’ the application code by loading files like config/bootstrap.php and any other setup code your application needs.

Because our new middleware replaces all the core provided dispatch filters, you should remember to remove all the relevant calls to DispatcherFactory::add() in config/bootstrap.php. The BaseApplication handles loading our bootstrap file, and we primarily need to define the middleware our application uses. I’ve used the term ‘middleware’ a few times so far but what is middleware? In a PSR7 application middleware has the following properties:

It is callable. Either because it is a Closure or it implements __invoke().

It returns a Response or raises an exception.

It supports the following signature __invoke($request, $response, $next)

Each middleware object is arranged into a stack, and when a request is handled each layer in the stack has the opportunity to update the response or replace the response and return it, delgate to the next layer, or throw an exception. Lets go over a simple example that adds the Origin header to a response:

The $next object is an important cog in the dispatch process. It permits a middleware object to delegate control to the ‘next’ middleware object in the stack. When using the PSR7 requests/responses it’s really important to remember that these objects are immutable. This means when you modify them, you need to re-assign the variable. For example:

What’s Next

Having a plugin is just the first step for PSR7 & CakePHP. I’ve published the plugin with the goal of getting feedback from you – the community. Over the next few months I plan on integrating the new PSR7 stack into CakePHP as the Cake\Http package. This package will contain the parts necessary to make a PSR7 Server, and PSR7 HTTP client.

The PSR7 stack will be an opt-in component as of 3.3, but it will be the default for new applications. In 3.4, the request object that controllers see, will implement the PSR7 interfaces but while still being mutable objects. In addition, redundant methods on both the request and response will be deprecated. The goal of the deprecations is to prepare for 4.0 where immutable PSR7 requests/responses will be standard across all of CakePHP. I also plan on adding PSR7 middleware for both DebugKit and AssetCompress to further prove out the implementation and provide examples of how to use the new interfaces.

Comments

Looking forward to see this as a default in CakePHP. A big step in the right direction. Thanks

Recent Artwork

Links

Mark is a designer and web-developer, working with standards compliant HTML and CSS. He has been building websites since 2000. Currently he is employed at Freshbooks as a developer, and actively contributes to open source projects specifically CakePHP. He uses this site as a place to share what he has learned and made.