Decoupled Libraries for PHP 5.4: The Aura Project
Upcoming SlideShare
Loading in...5

Decoupled Libraries for PHP 5.4: The Aura Project






Total Views
Views on SlideShare
Embed Views



11 Embeds 183 130 16 11 7 6 3 3 3 2 1
http://localhost 1



Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
Post Comment
Edit your comment

Decoupled Libraries for PHP 5.4: The Aura Project Decoupled Libraries for PHP 5.4: The Aura Project Presentation Transcript

  • Decoupled Libraries for PHP 5.4: The Aura Project php|tek 24 May 2012 @pmjones
  • Read These
  • About Me• 8 years USAF Intelligence• PHP since 1999• Developer, Senior Developer, Team Lead, Architect,VP Engineering• Aura project, benchmarking series, Solar framework, Savant template system, Zend_DB, Zend_View• PEAR Group member, ZCE Education Advisory Board
  • Overview• Background of libraries vs. frameworks• Principles of decoupled libraries• Individual Aura libraries
  • Some Background
  • Frameworks: Bad!• PHP 4 and early PHP 5: “framework” a bad word (“CMS” was ok)• Libraries and collections: Horde, PEAR, phpLib, phpClasses• Not unified in operation: different constructor signatures, different method verbiage, different usage idioms, tough to combine• Started Solar as a PHP 5 E_STRICT library collection
  • Frameworks: Good!• Rails: “framework” suddenly acceptable• Cake, CodeIgniter, Symfony, Zend• Tapped into user needs• All delivered as a monolithic whole• Re-branded Solar libraries as a framework
  • Frameworks: Good?• Seeing a shift away from framework devotion• Want to use just part of a framework? Difficult.• Download entire framework and try to use one part ...• ... except it has dependencies.• Have to set up parts you don’t care about.
  • Frameworks: Re-Evaluating• PHP 5.3: Lithium, Symfony 2, Zend Framework 2• Micro-frameworks: Glue, Limonade, Silex, Slim • Context, router/dispatcher, HTTP request/response, session manager• Component systems: Symfony (kind of)
  • Aura
  • Rewrite Solar• Solar Framework: 5+ years old• Monolithic, tough to use just parts of it• Extract components and rewrite using PHP 5.4• Independent, de-coupled library packages
  • Driving Principles• Libraries primary, framework secondary• No package depends on any other (self-contained)• Tests and assets encapsulated within package• Some repetition• Carry data across package boundaries using transfer objects
  • Use Dependency Injection• Solar used service locator and universal constructor• In Aura, that would mean a package dependency• So, all packages are set up for dependency injection• You can use any DI container you like
  • Service Locator Examplesclass Foo{ protected $db; public function __construct() { $this->db = Locator::get(db); }}class Foo{ protected $db; public function __construct(Locator $locator) { $this->db = $locator->get(db); }}
  • Dependency Injection Examples class Foo { protected $db; public function __construct(Database $db) { $this->db = $db; } } class Foo { protected $db; public function setDb(Database $db) { $this->db = $db; } }
  • Package Organization
  • Aura.Router
  • Description Aura Router is a PHP package that implements web routing. Given a URI path and a copy of $_SERVER, it will extract controller, action, andparameter values for a specific application route.
  • Instantiation// create the map object directly ...$map = require /path/to/Aura.Router/scripts/instance.php;// ... or add to autoloader, then:use AuraRouterMap;use AuraRouterRouteFactory;$map = new Map(new RouteFactory);
  • Creating Routes// add a simple named route without params$map->add(home, /);// add a simple unnamed route with params$map->add(null, /{:controller}/{:action}/{:id:(d+)});// add a complex named route$map->add(read, /blog/read/{:id}{:format}, [ params => [ id => (d+), format => (..+)?, ], values => [ controller => blog, action => read, format => .html, ],));
  • Matching Routes // get the incoming request URI path $path = parse_url($_SERVER[REQUEST_URI], PHP_URL_PATH); // get the route based on the path and server $route = $map->match($path, $_SERVER); The `match()` method does not parse the URI oruse `$_SERVER` internally. This is because different systems may have different ways of representing that information; e.g., through a URI object or a context object. As long as you can pass the string path and a server array, you can use Aura Router in your application foundation or framework.
  • Route Values$route = $map->match(/blog/read/42.json, $_SERVER);var_export($route->values);// shows these values:[ controller => blog, action => read, id => 42, format => .json,]
  • Dispatching Routes$params = $route->values;$class = ucfirst($params[controller]) . Page;unset($params[controller]);$method = $params[action] . Action;unset($params[action]);$object = new $class();echo $object->$method($params);
  • Micro-Framework Route$map->add(read, /blog/read/{:id}{:format}, [ params => [ id => (d+), format => (..+)?, ], values => [ controller => function ($args) { $id = (int) $args[id]; return "Reading blog ID {$id}"; }, format => .html, ],));
  • Micro-Framework Dispatcher$params = $route->values;$controller = $params[controller];unset($params[controller]);echo $controller($params);
  • Generating Paths$map->add(read, /blog/read/{:id}{:format} // ...// ...$path = $map->generate(read, [ id => 42, format => .atom,]);// $path => "/blog/read/42.atom"$href = htmlspecialchars($path, ENT_QUOTES, UTF-8);echo <a href="$href">Atom feed for this blog entry</a>;
  • Aura.Web
  • DescriptionThe Aura Web package provides tools to build web page controllers, including an `AbstractPage` for action methods, a`Context` class for disovering the request environment, and a `Response` transferobject that describes the eventual HTTP response. (Note that the `Response` transfer object is not itself an HTTP response.)
  • Setup// include all package files,// or add to your autoloaderinclude /path/to/Aura.Web/src.php;// create a page controllernamespace VendorPackageWeb;use AuraWebAbstractPage;class Page extends AbstractPage{ // controller body}
  • Instantiation and Callinguse VendorPackageWebPage;use AuraWebContext;use AuraWebResponse as ResponseTransfer;$params = [ action => hello, noun => world, format => .html,];$page = new Page( new Context($GLOBALS), new ResponseTransfer, $params);$response_transfer = $page->exec();
  • Important Parts• $params[‘action’] and $params[‘format’]• $this->context for get/post/files/accept/etc• $this->response for headers, cookies, content• $this->data for data to be rendered• $this->render() for rendering• (pre|post)(Exec/Action/Render) hooks
  • Action Methodnamespace VendorPackageWeb;use AuraWebAbstractPage;class Page extends AbstractPage{ protected function actionHello($noun = null) { $noun = htmlspecialchars($noun, ENT_QUOTES, UTF-8); $content = "Hello, {$noun}!"; $this->response->setContent($content); }}
  • Data and Renderingprotected function actionHello($noun = null){ $this->data->noun = $noun;}protected function render(){ // escape all data $data = []; foreach ((array) $this->data as $key => $val) { $data[$key] = htmlspecialchars($val, ENT_QUOTES, UTF-8); } // what format? if ($this->getFormat() == .json) { // json $this->response->setContentType(application/json); $content = json_encode([ success => true, content => $data, ]); } else { // html by default $content = "Hello, {$data[noun]}!"; } $this->response->setContent($content);}
  • Response Delivery• ResponseTransfer object is *not* an HTTP response• Must convert it to a real HTTP response• Allows any HTTP library, or none
  • Delivery Code$headers = $response_transfer->getHeaders();foreach ($headers as $label => $value) { header($label, $value);}$cookies = $response_transfer->getCookies();foreach ($cookies as $cookie) { setcookie( $cookie[value], $cookie[expire], $cookie[path], $cookie[domain], $cookie[secure], $cookie[httponly] );}echo $response_transfer->getContent();
  • Full-Stack Framework
  • Packages• Aura.Autoload • Aura.Router• Aura.Cli • Aura.Signal• Aura.Di • Aura.Sql• Aura.Http • Aura.View• Aura.Marshal • Aura.Web
  • Aura.Framework and System• Aura.Framework package to connect all the others together into a cohesive full-stack framework• “System” package to provide a project skeleton
  • Conclusion
  • • Frameworks vs libraries• Principles and packages• Still much to extract from Solar: filters, session manager, i18n/l10n• Google Beta• Join the project:
  • Thanks! @pmjones