Spekkoek plugin for CakePHP
 
 
 , (*1)
, (*1)
This plugin is a prototype for adding PSR7 middleware & request/response object
support to CakePHP. It should be considered experimental., (*2)
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., (*3)
- 
Spekkoek\ApplicationThe 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\MiddlewareStackA MiddlewareStack provides an interface for
building and manipulating the stack of middleware. TheApplicationis also
a middleware object that helps encapsulate the existing CakePHP dispatch
process.
- 
Spekkoek\ServerIs 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., (*4)
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:, (*5)
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:, (*6)
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., (*7)
Usage
This plugin fundamentally reworks your application's bootstrap process. It
requires replacing your webroot/index.php and implementing an Application class., (*8)
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, (*9)
Install the plugin with composer:, (*10)
composer require "markstory/cakephp-spekkoek:dev-master"
Next update your webroot/index.php to update, (*11)
Build the Application class
In your application's src directory create src/Application.php and put the following
in it:, (*12)
<?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:, (*13)
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());