An introduction to ICanBoogie
ICanBoogie is a high-performance micro-framework for PHP that provides essential features to build web applications. "micro" means that the core features of ICanBoogie are kept to the essential, its core is simple but greatly extensible and a variety of components can be used to complement its features with routing, controllers, views, message bus, modules, validation, mailer caching, ActiveRecord, internationalization, and many more… These components can be used on their own, they are integrated into the framework using special packages called bindings. Foreing packages, such as Symfony's dependency injection component, are bound in the same fashion.
Working with ICanBoogie
ICanBoogie tries to leverage the magic features of PHP as much as possible: getters/setters, invokable objects, array access, stringifiable objects, closures… to create a coherent framework which requires less typing and most of all less guessing. As a result, applications created with ICanBoogie have readable concise code and fluid flow.
Conventions and configuration
ICanBoogie comes with a few conventions: configurations are usually located in config
directories,
locale messages are usually located in locale
directories, cache and private/public files are
stored in a repository
directory, and an Application class must be defined by the application.
Components configure themselves thanks to ICanBoogie's Autoconfig feature and come with sensible
defaults. They won't require much from you other than a line in your composer.json
file.
Events
Events are everywhere in ICanBoogie, when the application boots, before a view is rendered, when a controller returns the result of an action, when an exception needs rescuing… It's really easy to hook into the even system to be notified when certain events occur inside the application and take action.
Getters and setters
Throughout ICanBoogie, magic properties are used in favor of explicit getters and setters. For
instance, DateTime instances provide a minute
property instead of getMinute()
and
setMinute()
methods.
Using a combination of getters, setters, properties, and property visibilities, you can create read-only properties, write-only properties, virtual properties; but also provide a default value until a property is set, control types and guard, and lazy load values.
Dependency injection, inversion of control
Some classes of ICanBoogie allow their methods to be defined at runtime, and since getters and setters are methods, this feature in often used to reverse control or provide dependencies. A more traditionnal approach is also available and is often used to instantiate message handlers and application services.
Objects as strings
If a string represents a serialized set of data ICanBoogie usually provides a class to make its manipulation easy. Instances can be created from strings, and in turn they can be used as strings. This applies to dates and times, time zones, time zone locations, HTTP headers, HTTP responses, database queries, and many more.
<?php
use ICanBoogie\DateTime;
$time = new DateTime('2013-05-17 12:30:45', 'Europe/Paris');
echo $time; // 2013-05-17T12:30:45+0200
echo $time->minute; // 30
echo $time->zone; // Europe/Paris
echo $time->zone->offset; // 7200
echo $time->zone->location; // FR,48.86667,2.3333348
echo $time->zone->location->latitude; // 48.86667
use ICanBoogie\HTTP\Headers;
$headers = new Headers;
$headers['Cache-Control'] = 'no-cache';
echo $headers['Cache-Control']; // no-cache
$headers['Cache-Control']->cacheable = 'public';
$headers['Cache-Control']->no_transform = true;
$headers['Cache-Control']->must_revalidate = false;
$headers['Cache-Control']->max_age = 3600;
echo $headers['Cache-Control']; // public, max-age=3600, no-transform
use ICanBoogie\HTTP\Response;
$response = new Response('ok', 200);
echo $response; // HTTP/1.0 200 OK\r\nDate: Fri, 17 May 2013 15:08:21 GMT\r\n\r\nok
/* @var $app ICanBoogie\Application */
echo $app->models['pages']->own->visible->filter_by_nid(12)->order('created_on DESC')->limit(5);
// SELECT * FROM `pages` `page` INNER JOIN `nodes` `node` USING(`nid`) WHERE (`constructor` = ?) AND (`is_online` = ?) AND (site_id = 0 OR site_id = ?) AND (language = "" OR language = ?) AND (`nid` = ?) ORDER BY created_on DESC LIMIT 5
Invokable objects
Objects performing a main action are simply invoked to perform that action. For instance, a prepared database statement is invoked to perform a command:
<?php
# DB statements
/* @var $app ICanBoogie\Application */
$statement = $app->models['nodes']->prepare('UPDATE {self} SET title = ? WHERE nid = ?');
$statement("Title 1", 1);
$statement("Title 2", 2);
$statement("Title 3", 3);
This applies to database connections, models, requests, responses, translators… and many more.
<?php
/* @var $app ICanBoogie\Application */
$pages = $app->models['pages'];
$pages('SELECT * FROM {self_and_related} WHERE YEAR(created_on) = 2013')->all;
# HTTP
use ICanBoogie\HTTP\Request;
$request = Request::from($_SERVER);
$response = $request();
$response();
# I18n translator
use ICanBoogie\I18n\Locale;
$translator = Locale::from('fr')->translator;
echo $translator('I can Boogie'); // Je sais danser le Boogie
Collections as arrays
Collections of objects always provide an array interface, whether they are records in the database, database connections, models, modules, header fields…
<?php
/* @var $app ICanBoogie\Application */
$app->models['nodes'][123]; // fetch record with key 123 in nodes
$app->modules['nodes']; // obtain the Nodes module
$app->connections['primary']; // obtain the primary database connection
/* @var $request ICanBoogie\HTTP\Request */
$request['param1']; // fetch param of the request named `param1`, returns `null` if it doesn't exists
/* @var $response ICanBoogie\HTTP\Response */
$response->headers['Cache-Control'] = 'no-cache';
$response->headers['Content-Type'] = 'text/html; charset=utf-8';
Creating instances from data
Most classes provide a from()
static method that creates instances from various data types.
This is especially true for sub-classes of the Prototyped class, which can create instances
from arrays of properties, and ActiveRecords are a perfect example of this feature:
<?php
use Icybee\Modules\Nodes\Node;
$node = new Node;
$node->uid = 1;
$node->title = "Title";
# or
$node = Node::from([ 'uid' => 1, 'title' => "Title" ]);
Some classes don't even provide a public constructor and rely solely on the from()
method. For
instance, Request instances can only by created using the from()
method:
<?php
use ICanBoogie\HTTP\Request;
# Creating the initial request from the $_SERVER array
$initial_request = Request::from($_SERVER);
# Creating a local XHR post request with some parameters
$custom_request = Request::from([
Request::OPTION_URI => '/path/to/controller',
Request::OPTION_IS_POST => true,
Request::OPTION_IS_LOCAL => true,
Request::OPTION_IS_XHR => true,
Request::OPTION_REQUEST_PARAMS => [
'param1' => 'value1',
'param2' => 'value2'
]
]);