PHP framework working with PHP5.3 who wants to be simple.
It only contains minimum viable features to make a web framework.
$ mkdir simple-framework
$ cd simple-framework
$ git init
$ git submodule add git@github.com:julesbou/SimpleFramework.git
$ cp SimpleFramework/Kernel.php.sample Kernel.php
$ mkdir templates
$ touch log.txtCreate an index.php file:
<?phprequire__DIR__.'/SimpleFramework/autoload.php';
require__DIR__.'/Kernel.php';
require__DIR__.'/Controller.php';
$kernel = newKernel('DEV');
echo$kernel->run();Create a Controller.php file:
<?phpclass Controller extendsSF\Controller
{
publicfunctionindexAction()
{
return$this->render('index.php', array('message' => 'Hello'));
}
}Create a file under templates/index.php:
<!DOCTYPE html><html><body><?php echo $message ?>!
</body></html>Your done! Go to your web browser to http://yoursite.com/index.php.
Container let you manage dependencies over your project. With it you can register services (a php class) and inject them into other services. No use of singletons.
The container has 2 states:
openYou can register new services in it.frozenYou can not register new services (it means that theContainer::freeze()method has been called).
Register something in it:
<?php$container = newSimpleFramework\Container();
// register a parameter$container['parameter_name'] = 'parameter_value';
// register a service$container['user_provider'] = newUserProvider();
// lazy register a service$container['auth'] = function($container) return newAuth($container['user_provider']);
};Then freeze the container, it means you can not register services in it anymore:
<?php$container->freeze();Get a service in the container:
<?php$auth = $container['auth'];Inside each controller you have access to the container:
<?phpnamespaceMyApp\Controller;
class UserController extends \SimpleFramework\Controller
{
publicfunctionindexAction()
{
$service = $this->container['service_name'];
}
}A controller can be a POPO (Plain old PHP object) or extends Controller, in the second case you have shortcut methods inside the SimpleFramework\Controller class.
The Container is passed to the controller in the first argument of his __construct() method.
Usage:
<?phpnamespaceMyApp\Controller;
class UserController extends \SimpleFramework\Controller
{
publicfunctionindexAction()
{
$url = $this->url('index');
//$url = $this->container['router']->generate('index');return$this->render('index.php');
// return $this->container['templating']->render('index.php');
}
}EventDispatcher helps you to make your code more extendible, reusable and flexible. The event dispatcher register listeners (or callback) that can be called later.
A simple use case is the wish to change session data of the logged-in user when we update the database, we can achieve this with the creation of a user.onChange event and add a listener to it:
<?phpuseSimpleFramework\EventDispatcher;
$dispatcher = newEventDispatcher();
// register the listener$dispatcher->listen('user.onChange', function($event) {
// refresh user session data
});
// call the listener$dispatcher->dispatch('user.onChange');SimpleFramework comes with 2 core events that let you return a response:
controller.beforecalled before the actioncontroller.aftercalled after the action
A simple use case is the wish to add a web-debug-toolbar:
<?phpuseSimpleFramework\Container;
useSimpleFramework\Kernel;
$container= newContainer();
$container['env'] = 'DEV';
$kernel = newKernel($container);
$container['event_dispatcher']->listen('controller.after', function($event) use($container) {
$content = $event['content'];
if ('DEV' === $container['env']) {
// rendering the toolbar html$toolbarHTML = $container['templating']->render('toolbar.php');
// append the toolbar to the htmlreturn$content.$toolbarHTML;
}
});
$kernel->run();The kernel is the main part of the framework, it is responsible for:
- build container
- choosing a route
- call some events (
controller.beforeandcontroller.after) - return response html
You can not use SF\Kernel directly, you have to extend it and declare some functions:
getRoutes(): return an array of routesgetTemplatingDirectories(): return an array of directories to find templatesgetTemplatingVars(): return an array of variables that get passed to the viewgetLogFile(): return the filename of the log file
For exemple:
<?phpclass MyKernel extends \SF\Kernel
{
protectedfunctiongetRoutes()
{
returnrequire__DIR__.'/routes.php';
}
protectedfunctiongetConfig();
{
returnarray('foo' => 'bar');
}
protectedfunctiongetTemplatingDirectories()
{
returnarray('' => __DIR__.'/app/templates');
}
protectedfunctiongetTemplatingVars()
{
returnarray(
'templating' => $this->container['templating'],
'router' => $this->container['router'],
);
}
protectedfunctiongetLogFile()
{
return__DIR__.'/log.txt';
}
}You can now instanciate the kernel like this:
<?php$kernel = newMyKernel('DEV');Router match an url to find a route, usage:
<?php// define some route$routes = array(
// minimal config'index' => array(
'pattern' => '/',
'controller' => 'MyNamespace\Controller',
'action' => 'edit',
),
// full config'edit' => array(
'pattern' => '/edit/{id}-{slug}',
'controller' => 'MyNamespace\Controller',
'action' => 'edit',
'method' => 'POST',
'requirements' => array('id' => '[0-9]+'),
),
);
$router = newSF\Router($routes);
// match a simple routelist($route, $params) = $router->match('/');
// match a route with placeholderslist($route, $params) = $router->match('/edit/9999-slug');
echo$params['id']; // 9999echo$params['slug']; // slug// route not foundtry {
$router->match('/unknown');
} catch (SF\HttpException$e) {
echo$e->getCode(); // 404
}
// generate urlecho$router->generate('index');
echo$router->generate('edit', array('id' => 9999, 'slug' => 'slug'));The controller look like this:
<?phpnamespaceMyNamespace;
class Controller
{
publicfunctionindexAction()
{
return'index';
}
publicfunctioneditAction($id, $slug)
{
return"editing $slug";
}
}Render a html template, pass variables to it, decorate it with a layout, usage:
<?php// keys are namespaces$templating = newSimpleFramework\Templating(array(
'' => __DIR__.'/templates',
'baz' => __DIR__.'/apps/baz/templates',
));
// render a template and pass variable to it$templating->render('foo.php', array('bar' => 'baz'));
// render a template and give it a layout$templating->render('foo.php', array('bar' => 'baz'), 'layout.php');
// with a namespace (/apps/baz/templates/index.php)$templating->render('baz:index.php');/templates/foo.php look like this:
<?phpecho$bar?>/templates/layout.php look like this:
<html><body><divclass="page"><h1>MyWebsite</h2><?php echo $content; ?></div></body></html>Run tests: phpunit