A prototype implementation of PSR7 middleware for CakePHP
PHP Other
Latest commit e8aac9e Mar 30, 2016 @markstory Add doc blocks to Runner.
Permalink
Failed to load latest commit information.
config Start the psr7 plugin approach. Feb 6, 2016
src Add doc blocks to Runner. Mar 30, 2016
tests Remove typehints on concrete types. Mar 30, 2016
.gitignore
.stickler.yml Fix linter name. Feb 28, 2016
.travis.yml Add codesniffer and try to fix travis failures. Feb 20, 2016
LICENSE Add license file. Feb 14, 2016
README.md Add some more details to the README. Mar 26, 2016
composer.json Constrain dependency better. Mar 28, 2016
phpunit.xml.dist Removed a forgotten letter on phpunit.xml Mar 26, 2016

README.md

Spekkoek plugin for CakePHP

Software License Build Status codecov.io

This plugin is a prototype for adding PSR7 middleware & request/response object support to CakePHP. It should be considered experimental.

Concepts

Spekkoek aims to provide PSR7 middleware for a CakePHP 3.x application. It adds a few new concepts to a CakePHP application that extend and enhance the existing abstractions.

  • Spekkoek\Application The Application object provides an object oriented approach to bootstrapping. This class is used to load bootstrapping and application configuration. It also provides hook methods for configuring middleware.
  • Spekkoek\MiddlewareStack A MiddlewareStack provides an interface for building and manipulating the stack of middleware. The Application is also a middleware object that helps encapsulate the existing CakePHP dispatch process.
  • Spekkoek\Server Is the entry point for a request/response. It consumes an application, and returns a response. The server's emit() method can be used to emit a response to the webserver SAPI.

There are PSR7 middleware versions of all the CakePHP core DispatchFilters. These are intended to be long term replacements for the CakePHP dispatch filters.

Middleware

Middleware is a closure or callable object that accepts a request/response and returns a response. Each middleware is also provided the next callable in the chain. This callable should be invoked if/when you want to delegate the response creation to the next middleware object. Middleware objects need to implement the following protocol:

public function __invoke($request, $response, $next)

Middleware objects must return a Response object. They can either augment the existing response object or create a new one, or delegate to the next middleware object by calling $next. A trivial example of middleware would be:

use Cake\Log\Log;
class TimingMiddleware
{
    public function __invoke($request, $response, $next)
    {
        $start = microtime(true);
        $response = $next($request, $response);
        $end = microtime(true);
        Log::info(sprintf(
            'Request to %s took %f seconds',
            $request->getUri()->getPath(),
            ($end - $start)
        ));
        return $response;
    }
}

Here we can see the $next object in action and also how to put some simple logic before and after the lower layers.

Usage

This plugin fundamentally reworks your application's bootstrap process. It requires replacing your webroot/index.php and implementing an Application class.

Installation & Getting Started

Unlike many other plugins, Spekkoek requires a more setup. Because it needs to augment how bootstrapping, requests and responses are handled you'll need to modify your webroot/index.php

Install the plugin with composer:

composer require "markstory/cakephp-spekkoek:dev-master"

Next update your webroot/index.php to update

Build the Application class

In your application's src directory create src/Application.php and put the following in it:

<?php
namespace App;

use Spekkoek\BaseApplication;
use Spekkoek\Middleware\AssetMiddleware;
use Spekkoek\Middleware\ErrorHandlerMiddleware;
use Spekkoek\Middleware\RoutingMiddleware;

class Application extends BaseApplication
{
    public function middleware($middleware)
    {
        // Catch any exceptions in the lower layers,
        // and make an error page/response
        $middleware->push(new ErrorHandlerMiddleware());

        // Handle plugin/theme assets like CakePHP normally does.
        $middleware->push(new AssetMiddleware());

        // Apply routing
        $middleware->push(new RoutingMiddleware());

        // The application is bound into the middleware
        // stack by the Server
        return $middleware;
    }
}

Update webroot/index.php

With your Application defined, you will need to update your webroot/index.php. It should look something like the following:

require dirname(__DIR__) . '/vendor/autoload.php';

use Spekkoek\Server;
use App\Application;

// Bind your application to the server.
$server = new Server(new Application(dirname(__DIR__) . '/config'));

// Run the request/response through the application
// and emit the response.
$server->emit($server->run());