Building Lithium Apps
Upcoming SlideShare
Loading in...5
×
 

Building Lithium Apps

on

  • 9,583 views

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.

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.

Statistics

Views

Total Views
9,583
Views on SlideShare
9,577
Embed Views
6

Actions

Likes
11
Downloads
91
Comments
3

1 Embed 6

http://linyo.ws 6

Accessibility

Categories

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.

Cancel

13 of 3 Post a comment

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • And thanks for the event and posting slides Nate!
    Are you sure you want to
    Your message goes here
    Processing…
  • 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.
    Are you sure you want to
    Your message goes here
    Processing…
  • Would love to hear an explanation of slide 49.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Building Lithium Apps Building Lithium Apps Presentation Transcript

    • BUILDING LITHIUM APPS LIKE A BOSS Pace University, NYC · 10-19-2010
    • ARCHITECTURE
    • architecture
    • noun ! the complex or carefully designed structure of ! something
    • noun ! Orderly arrangement of parts; structure
    • noun ! the conceptual structure and logical organization of a computer ! or computer-based system
    • “ARCHITECTURE” IN PHP
    • “PROCEDURAL”
    • “OBJECT-ORIENTED”
    • Procedural Object-Oriented
    • Procedural Object-Oriented
    • Aspect-Oriented Event-Driven Procedural PARADIGMS Declarative Functional Object-Oriented
    • Aspect-Oriented Event-Driven Procedural PARADIGMS Declarative Functional Object-Oriented
    • Aspect-Oriented Event-Driven Procedural PARADIGMS Declarative Functional Object-Oriented
    • Aspect-Oriented Event-Driven Procedural PARADIGMS Declarative Functional Object-Oriented
    • BOOTSTRAP / DISPATCH
    • index.php?url=/posts /posts
    • index.php?url=/posts config/bootstrap.php config/bootstrap/libraries.php /posts config/bootstrap/cache.php config/bootstrap/connections.php config/bootstrap/action.php ...
    • 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() )
    • 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) ) ) ));
    • 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' ));
    • STATICS & STATE
    • new lithiumactionRequest() $_GET $_POST $_SERVER
    • CONFIGURATION REQUEST
    • FILTERS
    • A.K.A. ASPECT-ORIENTED PROGRAMMING
    • 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); } }
    • 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); });
    • 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); });
    • CONTROLLERS
    • use appmodelsPosts; appcontrollersPostsController { public function index() { $posts = Posts::all(); return compact('posts'); } }
    • 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
    • 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
    • lithiumnethttpMedia { $formats = array( array( 'html' => array(...), 'posts' => ... 'json' => array(...), ) 'xml' => array(...), '...' ); }
    • new lithiumactionResponse()
    • Dispatcher index.php Controller new lithiumactionResponse() View
    • REQUEST / RESPONSE
    • 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() )); });
    • /** * 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')) )); });
    • WAX ON, WAX OFF
    • DEPENDENCIES
    • class User { public function somethingUseful() { Logger::info("Something useful is happening"); // ... } }
    • FALE class User { public function somethingUseful() { Logger::info("Something useful is happening"); // ... } b!! } Super dum
    • COUPLING RELEVANCE
    • Post::applyFilter('save', function($self, $params, $chain) { $entity =& $params['entity']; if (!$entity->exists()) { $entity->created = time(); } return $chain->next($self, $params, $chain); });
    • FALE Post::applyFilter('save', function($self, $params, $chain) { $entity =& $params['entity']; if (!$entity->exists()) { $entity->created = time(); } return $chain->next($self, $params, $chain); });
    • class WebService { protected $_classes = array( 'socket' => 'lithiumnethttpsocketContext', 'request' => 'lithiumnethttpRequest', 'response' => 'lithiumnethttpResponse' ); }
    • 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); });
    • REUSABILITY
    • 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 ....
    • Libraries::add('my_application', array( 'default' => true ));
    • 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 ));
    • DEMO...