Building Lithium Apps

10,458 views
10,290 views

Published on

Building Lithium Apps (Like a Boss) was a workshop presented on the structure and philosophy of the Lithium framework and its applications, and how best to take advantage of them.

Published in: Technology
3 Comments
11 Likes
Statistics
Notes
  • And thanks for the event and posting slides Nate!
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • If a filter is being applied to the Save function across all models, it shouldn't be a filter. Create a base class for your model classes and do it there.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Would love to hear an explanation of slide 49.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
10,458
On SlideShare
0
From Embeds
0
Number of Embeds
8
Actions
Shares
0
Downloads
101
Comments
3
Likes
11
Embeds 0
No embeds

No notes for slide

Building Lithium Apps

  1. 1. BUILDING LITHIUM APPS LIKE A BOSS Pace University, NYC · 10-19-2010
  2. 2. ARCHITECTURE
  3. 3. architecture
  4. 4. noun ! the complex or carefully designed structure of ! something
  5. 5. noun ! Orderly arrangement of parts; structure
  6. 6. noun ! the conceptual structure and logical organization of a computer ! or computer-based system
  7. 7. “ARCHITECTURE” IN PHP
  8. 8. “PROCEDURAL”
  9. 9. “OBJECT-ORIENTED”
  10. 10. Procedural Object-Oriented
  11. 11. Procedural Object-Oriented
  12. 12. Aspect-Oriented Event-Driven Procedural PARADIGMS Declarative Functional Object-Oriented
  13. 13. Aspect-Oriented Event-Driven Procedural PARADIGMS Declarative Functional Object-Oriented
  14. 14. Aspect-Oriented Event-Driven Procedural PARADIGMS Declarative Functional Object-Oriented
  15. 15. Aspect-Oriented Event-Driven Procedural PARADIGMS Declarative Functional Object-Oriented
  16. 16. BOOTSTRAP / DISPATCH
  17. 17. index.php?url=/posts /posts
  18. 18. index.php?url=/posts config/bootstrap.php config/bootstrap/libraries.php /posts config/bootstrap/cache.php config/bootstrap/connections.php config/bootstrap/action.php ...
  19. 19. index.php?url=/posts config/bootstrap.php config/bootstrap/libraries.php /posts config/bootstrap/cache.php config/bootstrap/connections.php config/bootstrap/action.php ... lithiumactionDispatcher::run( new lithiumactionRequest() )
  20. 20. config/bootstrap/cache.php Cache::config(array( 'local' => array( 'adapter' => 'Apc' ), 'distributed' => array( 'adapter' => 'Memcached', 'servers' => array( array('127.0.0.1', 11211, 100) array('127.0.0.2', 11211, 100) ) ) ));
  21. 21. config/bootstrap/connections.php Connections::add('default', array( 'development' => array( 'type' => 'MongoDb', 'host' => 'localhost', 'database' => 'foo' ), 'production' => array( 'type' => 'MongoDb', 'host' => 'db.host', 'database' => 'foo.prod' ) )); Connections::add('cassandra', array( 'type' => 'Cassandra', 'keyspace' => 'foo' ));
  22. 22. STATICS & STATE
  23. 23. new lithiumactionRequest() $_GET $_POST $_SERVER
  24. 24. CONFIGURATION REQUEST
  25. 25. FILTERS
  26. 26. A.K.A. ASPECT-ORIENTED PROGRAMMING
  27. 27. There are no routes here yet lithiumactionDispatcher { //... public static function run($request, ...) { // Pass the request to the Router $params = $classes['router']::process($request); // Do some checking... // Get a controller... return static::call($controller); } }
  28. 28. config/bootstrap/action.php Dispatcher::applyFilter('run', function($self, $params, $chain) { foreach (Libraries::get() as $name => $config) { // Some sanity checking goes here... include "{$config['path']}/config/routes.php"; } return $chain->next($self, $params, $chain); });
  29. 29. lithiumactionDispatcher { //... public static function run($request, ...) { // Pass the request to the Router $params = $classes['router']::process($request); // Do some checking... // Get a controller... // $controller = ... return static::call($controller); } } Dispatcher::applyFilter('run', function($self, $params, $chain) { foreach (Libraries::get() as $name => $config) { // Some sanity checking goes here... include "{$config['path']}/config/routes.php"; } return $chain->next($self, $params, $chain); });
  30. 30. CONTROLLERS
  31. 31. use appmodelsPosts; appcontrollersPostsController { public function index() { $posts = Posts::all(); return compact('posts'); } }
  32. 32. class WeblogController < ActionController::Base def index @posts = Post.find :all respond_to do |format| format.html format.xml { render :xml => @posts.to_xml } format.rss { render :action => "feed.rxml" } end end end
  33. 33. class WeblogController < ActionController::Base def index @posts = Post.find :all respond_to do |format| format.html format.xml { render :xml => @posts.to_xml } format.rss { render :action => "feed.rxml" } end end end
  34. 34. lithiumnethttpMedia { $formats = array( array( 'html' => array(...), 'posts' => ... 'json' => array(...), ) 'xml' => array(...), '...' ); }
  35. 35. new lithiumactionResponse()
  36. 36. Dispatcher index.php Controller new lithiumactionResponse() View
  37. 37. REQUEST / RESPONSE
  38. 38. Router::connect('/photos/{:id:[0-9a-f]{24}}.jpg', array(), function($request) { return new Response(array( 'type' => 'jpg', 'body' => Photo::first($request->id)->file->getBytes() )); });
  39. 39. /** * This handles both the home page and the archives pages. */ Router::connect('/{:page}', array('page' => 1), array( 'pattern' => '@^/?(?P<page>d+)$|^/?$@', 'keys' => array('page' => true), 'handler' => function($request) use ($render) { $page = intval($request->page); $posts = Posts::recent(compact('page')); return new Response(array( 'body' => $render('index', compact('posts'), compact('request')) )); }) ); /** * Handles adding new posts. */ Router::connect('/add', array(), function($request) use ($render) { $post = Posts::create(); if (($request->data) && $post->save($request->data)) { return new Response(array('location' => '/')); } return new Response(array( 'body' => $render('edit', compact('post'), compact('request')) )); }); /** * Edits existing pages. */ Router::connect('/{:slug:[a-z0-9-]+}/edit', array('edit' => true), function($request) use ($render) { $conditions = array('slug' => $request->slug); $post = Posts::first(compact('conditions')); if (($request->data) && $post->save($request->data)) { return new Response(compact('request') + array('location' => array('slug' => $post->slug))); } return new Response(array( 'body' => $render('edit', compact('post'), compact('request')) )); }); /** * Handles single page views. */ Router::connect('/{:slug:[a-z0-9-]+}', array(), function($request) use ($render) { $conditions = array('slug' => $request->slug, 'published' => true); $post = Posts::first(compact('conditions')); return new Response(array( 'status' => $post ? 200 : 404, 'body' => $render($post ? 'view' : 'error', compact('post'), compact('request')) )); });
  40. 40. WAX ON, WAX OFF
  41. 41. DEPENDENCIES
  42. 42. class User { public function somethingUseful() { Logger::info("Something useful is happening"); // ... } }
  43. 43. FALE class User { public function somethingUseful() { Logger::info("Something useful is happening"); // ... } b!! } Super dum
  44. 44. COUPLING RELEVANCE
  45. 45. Post::applyFilter('save', function($self, $params, $chain) { $entity =& $params['entity']; if (!$entity->exists()) { $entity->created = time(); } return $chain->next($self, $params, $chain); });
  46. 46. FALE Post::applyFilter('save', function($self, $params, $chain) { $entity =& $params['entity']; if (!$entity->exists()) { $entity->created = time(); } return $chain->next($self, $params, $chain); });
  47. 47. class WebService { protected $_classes = array( 'socket' => 'lithiumnethttpsocketContext', 'request' => 'lithiumnethttpRequest', 'response' => 'lithiumnethttpResponse' ); }
  48. 48. use appmodelsPost; use li3_elasticsearchextensionsdatabehaviorSearchable; Post::applyFilter('save', function($self, $params, $chain) { $entity =& $params['entity']; $id = $entity->guid; Searchable::add('public_posts', 'stream', $id, $entity->to('array')); return $chain->next($self, $params, $chain); });
  49. 49. REUSABILITY
  50. 50. config/bootstrap/libraries.php Make conditional define('LITHIUM_APP_PATH', dirname(dirname(__DIR__))); define('LITHIUM_LIBRARY_PATH', LITHIUM_APP_PATH . '/../libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php'; require LITHIUM_LIBRARY_PATH . '/lithium/core/StaticObject.php'; Remove when require LITHIUM_LIBRARY_PATH . '/lithium/util/Collection.php'; require LITHIUM_LIBRARY_PATH . '/lithium/util/collection/Filters.php'; require LITHIUM_LIBRARY_PATH . '/lithium/util/Inflector.php'; require require LITHIUM_LIBRARY_PATH LITHIUM_LIBRARY_PATH . . '/lithium/util/String.php'; '/lithium/core/Adaptable.php'; plugin-izing require LITHIUM_LIBRARY_PATH . '/lithium/core/Environment.php'; require LITHIUM_LIBRARY_PATH . '/lithium/net/Message.php'; require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Message.php'; require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Media.php'; require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Request.php'; require ....
  51. 51. Libraries::add('my_application', array( 'default' => true ));
  52. 52. my_awesome_plugin/ config/ bootstrap.php Required routes.php Optional anything_in_an_app/ Happens in the filter we saw in action.php Unless you Libraries::add('my_awesome_plugin', array( 'bootstrap' => false disable it ));
  53. 53. DEMO...

×