Random thoughts

conduit middleware for php

Long back, I happened to talk with Beau Simensen about stackphp on #auraphp channel. It was hard for me to digest when I noticed it need symfony/http-kernel and its dependencies.

After a few months, I started to like the middleware approach of slim framework and wanted to push it to aura. But nothing happened there.

Conduit to rescue

Conduit is a Middleware for PHP built by Matthew Weier O'Phinney lead of Zend framework. Conduit supports the current PSR-7 proposal. I believe like the many PSR's, PSR-7 will be a revolution in the PHP world. Conduit is really a micro framework and can grow with your project.

Starting your project

I hope you know about the tool composer and know about PHP 5.3 to follow the tutorial.

mkdir sample-project
cd sample-project
composer require "phly/conduit:0.10.*"
mkdir web

We have created an extra web folder, so it acts as the document root. Create an index.php file in the web folder and lets start serving our first Hello conduit! message.

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

use Phly\Conduit\Middleware;
use Phly\Http\Server;

$app = new Middleware();
$app->pipe('/', function ($request, $response, $next) {
    return $response->write('Hello conduit!')->end();
});
$server = Server::createServer($app,
  $_SERVER,
  $_GET,
  $_POST,
  $_COOKIE,
  $_FILES
);
$server->listen();

Start your web server, or fire your built in PHP server.

php -S localhost:8000 web/index.php -t web

Point your browser to http://localhost:8000 and you can see Hello conduit!.

Middlewares

Conduit route is very limited and will not handle dynamic routing. So we need a router middleware to resuce. Let us build our first router middleware. If you check the docs middleware can be a closure, invokable objects, array callback etc. We will stick with closure in the examples.

The idea is same even if you are using a different library.

  1. Get the path via $request->getUri()->getPath()
  2. Check router if the path is matching
  3. If
    • no call the next middleware in stack. ie return $next()
    • yes execute the controller and return back the response

Be sure that if you change something you need to return the response. Because Request and Response are immutable.

In-order to build something like the above, we need a router library which can handle routing, and a dispatcher library which can handle the necessary operation when a route is found.

Install the dependencies.

composer require "aura/router:~2.0" "aura/dispatcher:~2.0"

The router middleware will look like as below.

<?php
$router = new \Aura\Router\Router(
    new \Aura\Router\RouteCollection(new \Aura\Router\RouteFactory),
    new \Aura\Router\Generator
);
$dispatcher = new \Aura\Dispatcher\Dispatcher(array(), 'controller', 'action');

$app->pipe(function ($request, $response, $next) use ($router, $dispatcher) {
    $path = $request->getUri()->getPath();
    $route = $router->match($path, $request->getServerParams());
    if (! $route) {
        return $next();
    }
    $params = $route->params;
    $params['request'] = $request;
    $params['response'] = $response;
    $result = $dispatcher->__invoke($params);
    if ($result instanceof \Psr\Http\Message\ResponseInterface) {
        $response = $result;
    } else {
        $response = $response->write($result)->end();
    }
    return $response;
});

Now your router middleware can handle dynamic things. You can see the full example over gist.

You may need an authentication middleware to check whether the user is authenticated, or a content negotiation middleware to set the corresponding Content-Type header in the response.

I have created a skelton project which have a router middleware, authentication middleware and negotiation middleware with the help of a few libraries. Less libraray means less code to maintain, easy to understand and debug the code behind the scenes.

Today, I noticed one question over reddit Moving to a real framework.. need help with the migration wrote my suggestion how conduit + aura can help.

Play and enjoy!

Menu