alexbilbie/proton

Micro PHP framework

1.4.1 2015-03-26 17:35 UTC

README

Latest Version Software License Build Status Coverage Status Quality Score

Proton is a StackPHP compatible micro framework.

Under the hood it uses League\Route for routing, League\Container for dependency injection, and League\Event for event dispatching.

Installation

Just add "alexbilbie/proton": "~1.4" to your composer.json file.

Setup

Basic usage with anonymous functions:

// index.php
<?php

require __DIR__.'/../vendor/autoload.php';

$app = new Proton\Application();

$app->get('/', function ($request, $response) {
    $response->setContent('<h1>It works!</h1>');
    return $response;
});

$app->get('/hello/{name}', function ($request, $response, $args) {
    $response->setContent(
        sprintf('<h1>Hello, %s!</h1>', $args['name'])
    );
    return $response;
});

$app->run();

Basic usage with controllers:

// index.php
<?php

require __DIR__.'/../vendor/autoload.php';

$app = new Proton\Application();

$app['HomeController'] = function () {
    return new HomeController();
};

$app->get('/', 'HomeController::index'); // calls index method on HomeController class

$app->run();
// HomeController.php
<?php

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class HomeController
{
    public function index(Request $request, Response $response, array $args)
    {
        $response->setContent('<h1>It works!</h1>');
        return $response;
    }
}

Basic usage with StackPHP (using Stack\Builder and Stack\Run):

// index.php
<?php
require __DIR__.'/../vendor/autoload.php';

$app = new Proton\Application();

$app->get('/', function ($request, $response) {
    $response->setContent('<h1>It works!</h1>');
    return $response;
});

$stack = (new Stack\Builder())
    ->push('Some/MiddleWare') // This will execute first
    ->push('Some/MiddleWare') // This will execute second
    ->push('Some/MiddleWare'); // This will execute third

$app = $stack->resolve($app);
Stack\run($app); // The app will run after all the middlewares have run

Debugging

By default Proton runs with debug options disabled. To enable debugging add

$app['debug'] = true;

Proton has built in support for Monolog. To access a channel call:

$app->getLogger('channel name');

For more information about channels read this guide - https://github.com/Seldaek/monolog/blob/master/doc/usage.md#leveraging-channels.

Custom exception decoration

$app->setExceptionDecorator(function (\Exception $e) {
    $response = new \Symfony\Component\HttpFoundation\Response;
    $response->setStatusCode(500);
    $response->setContent('Epic fail!');
    return $response;
});

Events

You can intercept requests and responses at three points during the lifecycle:

request.received

$app->subscribe('request.received', function ($event) {
    // access the request using $event->getRequest()
})

This event is fired when a request is received but before it has been processed by the router.

response.created

$app->subscribe('response.created', function ($event) {
    // access the request using $event->getRequest()
    // access the response using $event->getResponse()
})

This event is fired when a response has been created but before it has been output.

response.sent

$app->subscribe('response.sent', function ($event) {
    // access the request using $event->getRequest()
    // access the response using $event->getResponse()
})

This event is fired when a response has been output and before the application lifecycle is completed.

Custom Events

You can fire custom events using the event emitter directly:

// Subscribe
$app->subscribe('custom.event', function ($event, $time) {
    return 'the time is '.$time;
});

// Publish
$app->getEventEmitter()->emit('custom.event', time());

Dependency Injection Container

Proton uses League/Container as its dependency injection container.

You can bind singleton objects into the container from the main application object using ArrayAccess:

$app['db'] = function () {
    $manager = new Illuminate\Database\Capsule\Manager;

    $manager->addConnection([
        'driver'    => 'mysql',
        'host'      => $config['db_host'],
        'database'  => $config['db_name'],
        'username'  => $config['db_user'],
        'password'  => $config['db_pass'],
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci'
    ], 'default');

    $manager->setAsGlobal();

    return $manager;
};

or by accessing the container directly:

$app->getContainer()->singleton('db', function () {
    $manager = new Illuminate\Database\Capsule\Manager;

    $manager->addConnection([
        'driver'    => 'mysql',
        'host'      => $config['db_host'],
        'database'  => $config['db_name'],
        'username'  => $config['db_user'],
        'password'  => $config['db_pass'],
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci'
    ], 'default');

    $manager->setAsGlobal();

    return $manager;
});

Multitons can be added using the add method on the container:

$app->getContainer()->add('foo', function () {
        return new Foo();
});

Service providers can be registered using the register method on the Proton app or addServiceProvider on the container:

$app->register('\My\Service\Provider');
$app->getContainer()->addServiceProvider('\My\Service\Provider');

For more information about service providers check out this page - http://container.thephpleague.com/service-providers/.

For easy testing down the road it is recommended you embrace constructor injection:

$app->getContainer()->add('Bar', function () {
        return new Bar();
});

$app->getContainer()->add('Foo', function () use ($app) {
        return new Foo(
            $app->getContainer()->get('Bar')
        );
});