A dead simple PHP framework
PHP JavaScript
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
layouts
lib
logs
public
swinger
views
README.md
config.php
index.php
swinger.php

README.md

WARNING

NOTE: This framework is under construction. Heavy changes are made. Do not use it.

The following documentation is not valid.

General description

Swinger is inspired from the Ruby framework Sinatra. This is a "VC" (View Controller) framework for PHP. Swinger is dead simple and extremely lightweight, in comparison to ZF of Symphony.

You can use it to create:

  • Simple WEB sites.
  • Technical user interfaces.
  • WEB sites for low power infrastructure.
  • Provisioning interfaces.
  • ...

For these kinds of applications, using ZF of Symphony is like using a sledge-hammer to crack a nut.

Swinger provides:

  • Basic layout/view support. Swinger does not integrate fancy template engines, since PHP is already suited for this application. A layout, or a view, is just a PHP file.
  • Controller. The organisation of URLs is totally free. You don't have to follow the "controller/action" rule. The URL associated to a controller can be defined as a regular expression.
  • Basic, but powerful auto-load management. Auto-load management is really basic, but it offers the best performance in terms of speed, when the application runs in "production mode".
  • Registry.
  • Nice error message in case you made an error with the framework's API.

Installation

The installation involves two steps:

  • Step 1: install the framework.
  • Step 2: configuration your WEB server.

Installing the framework

In this document, we assume that you put your WEB application in the directory "/home/www/my_application". "/home/www/my_application" is called the "application's directory".

Just uncompress the Swinger's archive in your application's directory (that is "/home/www/my_application").

You should have the following entries:

  • /home/www/my_application/README.md: This is the GitHub's README file. It uses GitHub Flavored Markdown (GFM). You can delete this file.
  • /home/www/my_application/config.php: This is where you configure the framework and where you (should) put your application's configuration.
  • /home/www/my_application/data: Swinger uses this directory to put temporary files.
  • /home/www/my_application/doxygen.conf: This is the Doxygen's configuration file. Doxygen is used to produce documentation from the source code. You can delete this file.
  • /home/www/my_application/index.php: This is the entry point for your application.
  • /home/www/my_application/layouts: This directory is used to store the layouts.
  • /home/www/my_application/lib: This directory is used to store your PHP code.
  • /home/www/my_application/logs: This directory should be used to put LOG files.
  • /home/www/my_application/public: This directory is used to store any files other that PHP files (images, CSS, javascript...).
  • /home/www/my_application/views: This directory is used to store the views.

WARNING

You must check the files' permissions.

  • /home/www/my_application/data: Make sure that your WEB user has "execute", "read" and "write" permissions on this directory.
  • /home/www/my_application/layouts: Make sure that your WEB user has "execute" and "read" permissions on this directory and sub-directories. Make sure that your WEB user has "read" permissions on all PHP files under this directory.
  • /home/www/my_application/lib: Make sure that your WEB user has "execute" and "read" permissions on this directory and sub-directories. Make sure that your WEB user has "read" permission on all PHP files under this directory.
  • /home/www/my_application/logs: If you plan to put LOG files under this directory, then make sure that your WEB user has "execute", "read" and "write" permission on this directory.
  • /home/www/my_application/public: Make sure that your WEB user has "execute" and "read" permissions on this directory and sub-directories. Make sure that your WEB user has "read" permission on all files under this directory.
  • /home/www/my_application/views: Make sure that your WEB user has "execute" and "read" permissions on this directory and sub-directories. Make sure that your WEB user has "read" permission on all PHP files under this directory.

Configuring the WEB server

Using Apache's virtual host

Template

Here is a basic virtual host definition for Swinger.

This example assumes that:

  • You put your Swinger application in the directory "/home/www/my_application". You must change it according to your environment.

  • The host name for the virtual host is "my_application.com". You must change it according to your environment.

    <VirtualHost *:80>
    
    	# Replace "/home/www/my_application" by whatever you need.
       	DocumentRoot "/home/www/my_application"
    
       	<Directory />
           	AllowOverride All
           	Order Allow,Deny
           	Allow from all
       	</Directory>
    
    	# Replace "my_application.com" by whatever you need.
       	ServerName my_application.com
    
       	Options +FollowSymLinks 
       	RewriteEngine on
    
    	# First rule
    	# If you use other type of files than those listed below (.html, .ico, ...), you must add them.
    	RewriteCond %{REQUEST_URI} \.(html|ico|bmp|svg|jpg|jpeg|gif|png|js|css|swf|zip|tar|gz)$ [nocase]
    	RewriteRule ^(.*)$ /public/$1 [last]
    
    	# Second rule
       	RewriteCond %{DOCUMENT_ROOT}/$1 !-f
       	RewriteRule ^(.*)$ /lib/System/Swing.php/$1 [last,qsappend]
    
    </VirtualHost>
    

Notes

The first rewrite rule is:

RewriteCond %{REQUEST_URI} \.(html|ico|bmp|svg|jpg|jpeg|gif|png|js|css|swf|zip|tar|gz)$ [nocase]
RewriteRule ^(.*)$ /public/$1 [last]

It means: Any URL that points to a file which extension is included in the given list (.html, .ico...) is treated as a static file and will be searched under the directory "/home/www/my_application/public/".

For example: "http://my_application.com/photo.png" refers to the file "/home/www/my_application/public/photo.png".

For example: "http://my_application.com/swinger/main.css" refers to the file "/home/www/my_application/public/swinger/main.css".

The second rewrite rule is:

RewriteCond %{DOCUMENT_ROOT}/$1 !-f
RewriteRule ^(.*)$ /lib/System/Swing.php/$1 [last,qsappend]

It means: any HTTP request (other that those which match the first rewrite rule) will be "redirected" to the script "/lib/System/Swing.php".

For example: "http://my_application.com/foo/bar" will execute the script "/home/www/my_application/lib/System/Swing.php".

Quick start

In the section we assume that your application is accessible through the URL "http://my_application.com". This depends on the configuration of your WEB server.

The basic "Hello World"

Edit the file "index.php" (in the application's directory).

<?php

// <=> Controller::register('all',  '/', 'index', 'TEXT');
Controller::register('all',  '/', 'index');

function index() { return "Hello world!"; }

?>

This means: any type of request ("GET" or "POST") on the URL "http://my_application.com" will execute the function "index()".

The example above is equivalent to the example below.

<?php

// Notice the last parameter "SCREEN".
Controller::register('all',  '/', 'index', 'SCREEN');

// Notice that we perform an "echo".
function index() { echo "Hello world!"; }

?>

And what if you want to return some JSON data ?

<?php

// Notice the last parameter "JSON".
Controller::register('all',  '/', 'index', 'JSON');

// Notice that we just return the value.
function index() { return array('text' => 'Hello world!'); }

?>

GET or POST ?

Now, you want "Hello world" to be printed only on a GET request.

<?php

Controller::register('get',  '/', 'index');

function index() { return "Hello world!"; }

?>

But I want to do something if I receive a POST request! No problem :

<?php

Controller::register('get',  '/', 'index');
Controller::register('post',  '/', 'calculate', 'JSON');

function index() { return "Hello world!"; }
function calculate() { return array('data' => 0); }

?>

More complex URLs

So far, the application only treats requests on the top level URL. Let's register other URLs.

<?php

Controller::register('get',  '/', 'index');
Controller::register('get',  '/meteo', 'meteo', 'SCREEN');
Controller::register('get',  '/meteo/next', 'tomorrow', 'TEXT');

function index() { return "Hello world!"; }
function meteo() { echo "Sun"; }
function tomorrow() { return "Rain"; }

?>

GET http://my_application.com => execute the function index().

GET http://my_application.com/meteo => execute the function meteo().

GET http://my_application.com/meteo/next => execute the function tomorrow().

Even more complex URL: regular expression

<?php

Controller::register('get',  new Regexp('/^\/jump(\/(left|right)?)?$/'), 'jumper');

function jumper($captures)
{
	$where = count($captures) > 2 ? $captures[2] : 'nowhere';
	return "Jump to $where";
}

?>

GET http://my_application.com/jump => will print "Jump to nowhere".

GET http://my_application.com/jump/left => will print "Jump to left";

GET http://my_application.com/jump/right => will print "Jump to right";

<?php

Controller::register('get',  new Regexp('/^\/jump(\/([a-z0-9]+)?)?$/'), 'jumper');

function jumper($captures)
{
	$where = count($captures) > 2 ? $captures[2] : 'nowhere';
	return "Jump to $where";
}

?>

GET http://my_application.com/jump => will print "Jump to nowhere".

GET http://my_application.com/jump/toto => will print "Jump to toto".

GET http://my_application.com/jump/foo123 => will print "Jump to foo123".

...

A catch-all controller

<?php

Controller::register('get',  '/', 'index');
Controller::selDefault('defaultController', 'TEXT');

function index() { return "Hello world!"; }
function defaultController() { return 'This is the default controller!'; }

?>

GET http://my_application.com => will print "Hello world!".

Any other request will print "This is the default controller!".

Getting information about the request

See class Request.

Request::get($in_name)

Any value available from the PHP "superglobal" $_SERVER is accessible through the method Request::get($in_name).

$in_name Name of the value to retrieve.

The method returns the searched value, or null if no value is found.

For example, you want to know the client's IP address :

$client_ip = Request::get('remote_addr');

// or

$client_ip = Request::get('REMOTE_ADDR');

// or

$client_ip = Request::get('Remote_Addr');

if (is_null($client_ip)) { ... }

Request::values()

All values sent by the client is accessible through the method Request::values().

For example :

// $vars is just $_GET or $_POST (see PHP documentation).
// $vars is an associative array.
$vars = Request::values(); 
foreach ($vars as $name => $value) { ... }

Request::value($in_name)

If you only need to retrieve a single value, just use the method Request::value($in_name).

$in_name Name of the value to retrieve.

If the value is set, then the method returns it. Otherwise, the method returns the value FALSE.

For example :

$login = Request::value('login');
if (FALSE === $login) { ... }

The controller's API in details

See class Controller.

The class Controller exports three methods :

  • register(): bind a controller to a given URL ans a HTTP method (defined by a string or by a regular expression).
  • selDefault(): set a "catch all" controller.
  • jumpTo(): stop the execution of the current controller and start executing a new one.

Controller::register($in_method, $in_expression, $in_function, $in_opt_expected="TEXT")

Bind a controller to a URL and a HTTP method.

$in_method Name of the HTTP method.

It can be:

  • "GET"
  • "POST"
  • "ALL" (or null). "ALL" means "GET or POST".

$in_expression Expression that represents the controller.

It can be:

  • A string. For example: "/user/login" or "/command/map/ul".
  • A regular expression: For example: new Regexp('/^/jump(/(left|right)?)?$/').

$in_function The name of the function that will be executed.

The function's signature is:

function myController([$capture]) { ... }

The argument "$capture" is optional.

  • If you define the URL through a string, then this argument is useless.
  • If you define the URL through a regular expression, then this argument may be necessary. It depends if your regular expression includes capture parenthesis. If you're the regular expression contains capture parenthesis, then you need a way to retrieve the captured strings. You do so through the argument, which is an array. Please see the documentation for preg_match().

$in_opt_expected The expected controller's output.

It could be:

  • "TEXT": the controller must return a string. This is the default value.
  • "SCREEN": the controller must echo text to the standard output.
  • "JSON": the controller must return an array.

For examples :

// URL is a simple string.

Controller::register('get',  '/command/hello', 'getHello');
Controller::register('post', '/command/hello', 'postHello', 'SCREEN');
Controller::register('all',  '/command/bye',   'allBye', 'JSON');

function getHello()  { ... return $string; }
function postHello() { ... echo $string; }
function allBye()    { ... return array('status' => OK); }

// URL is a regular expression.

Controller::register('get',  new Regexp('/^\/jump(\/(left|right)?)?$/'), 'jumper');

function jumper($captures)
{
	$where = count($captures) > 2 ? $captures[2] : 'nowhere';
	return "You want to go to $where!";
}

See index.php for more examples.

Controller::selDefault($in_name, $in_opt_format='TEXT')

Register a default controller that will be executed if no specific controller has been registered for the current URL.

$in_name Name of the function to execute.

$in_opt_format The expected controller's output.

It could be:

  • "TEXT": the controller must return a string. This is the default value.
  • "SCREEN": the controller must echo text to the standard output.
  • "JSON": the controller must return an array.

For example:

Controller::selDefault('defaultController', 'TEXT');

function defaultController()
{
	return 'This is the default controller!';
}

Controller::jumpTo($in_controller_name)

Stop the execution of the current controller and start executing a new one.

$in_controller_name Name of the controller to execute.

For example:

Controller::register('get',  new Regexp('/^\/jump(\/(left|right)?)?$/'), 'jumper');

function jumper($captures)
{
	// This controller will just give control to the controller "nextStep".
	$where = count($captures) > 2 ? $captures[2] : 'nowhere';
	Registry::set('destination', $where);
	Controller::jumpTo('nextStep');
	
	// The following code will __NOT__ be executed !!!
	exit(-1);   // __NOT__ executed !!!
}

function nextStep()
{
	// Please note that this controller is _NOT_ declared (Controller::register(...)).
	// Therefore, the output format is "TEXT".
	return 'Executing nextStep() on "' . Registry::get('destination') . '"';
}

The registry

The registry is just a convenient place where you can store global variables.

See class Registry.

Note that the class' code should be very clear.

Registry::set($in_name, $in_value)

Store a value in the registry.

$in_name Name of the value.

$in_value The value.

For example:

Registry::set('level', 0);

Registry::get($in_name)

Retrieve a value from the registry.

$in_name Name of the value to retrieve.

If the requested value is not recorded in the registry, then the method raises an exception.

For example:

Registry::set('level', 0);
// ...
$level = Registry::get('level');

ls If the requested value is already recorded in the registry, then the method raises an exception.

Registry::exists($in_name)

Test if a value is recorded in the registry.

$in_name Name of the value.

If the value is recorded in the registry, then the method returns the value TRUE. Otherwise, it returns the value FALSE.

For example:

if (FALSE !== Registry::exists('level'))
{
	// The value 'level' is recorded in the registry.
}