Decoupled Libraries for PHP 5.4: The Aura Project

  • 6,129 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
6,129
On Slideshare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
34
Comments
0
Likes
8

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Decoupled Libraries for PHP 5.4: The Aura Project php|tek 24 May 2012 joind.in/6495 paul-m-jones.com @pmjones
  • 2. Read These
  • 3. 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
  • 4. Overview• Background of libraries vs. frameworks• Principles of decoupled libraries• Individual Aura libraries
  • 5. Some Background
  • 6. 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
  • 7. 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
  • 8. 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.
  • 9. 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)
  • 10. Aura
  • 11. 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
  • 12. 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
  • 13. 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
  • 14. 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); }}
  • 15. 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; } }
  • 16. Package Organization
  • 17. Aura.Router
  • 18. 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.
  • 19. 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);
  • 20. 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, ],));
  • 21. 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.
  • 22. 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,]
  • 23. 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);
  • 24. 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, ],));
  • 25. Micro-Framework Dispatcher$params = $route->values;$controller = $params[controller];unset($params[controller]);echo $controller($params);
  • 26. 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>;
  • 27. Aura.Web
  • 28. 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.)
  • 29. 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}
  • 30. 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();
  • 31. 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
  • 32. 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); }}
  • 33. 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);}
  • 34. Response Delivery• ResponseTransfer object is *not* an HTTP response• Must convert it to a real HTTP response• Allows any HTTP library, or none
  • 35. 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();
  • 36. Full-Stack Framework
  • 37. Packages• Aura.Autoload • Aura.Router• Aura.Cli • Aura.Signal• Aura.Di • Aura.Sql• Aura.Http • Aura.View• Aura.Marshal • Aura.Web
  • 38. 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
  • 39. Conclusion
  • 40. • Frameworks vs libraries• Principles and packages• Still much to extract from Solar: filters, session manager, i18n/l10n• Google Beta• Join the project: auraphp.github.com
  • 41. Thanks! joind.in/6495auraphp.github.compaul-m-jones.com @pmjones