Skip to content

Repository files navigation

Simple Framework

PHP framework working with PHP5.3 who wants to be simple.

It only contains minimum viable features to make a web framework.

Installation

Create the project structure

$ 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.txt

Create the index file

Create an index.php file:

<?phprequire__DIR__.'/SimpleFramework/autoload.php';
require__DIR__.'/Kernel.php';
require__DIR__.'/Controller.php';
$kernel = newKernel('DEV');
echo$kernel->run();

Create the Controller

Create a Controller.php file:

<?phpclass Controller extendsSF\Controller
{
publicfunctionindexAction()
{
return$this->render('index.php', array('message' => 'Hello'));
}
}

Create the template file

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.

Internals

Container

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:

  • open You can register new services in it.
  • frozen You can not register new services (it means that the Container::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'];
}
}

Controller

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');
}
}

Event Dispatcher

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.before called before the action
  • controller.after called 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();

Kernel

The kernel is the main part of the framework, it is responsible for:

  • build container
  • choosing a route
  • call some events (controller.before and controller.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 routes
  • getTemplatingDirectories() : return an array of directories to find templates
  • getTemplatingVars() : return an array of variables that get passed to the view
  • getLogFile() : 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

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";
}
}

Templating

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>

Contributing

Run tests: phpunit

About

Minimal PHP framework (largely inspired from Symfony)

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages