building lithium apps

Post on 10-May-2015

9.887 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

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.

TRANSCRIPT

BUILDING LITHIUMAPPS LIKE A BOSSPace University, NYC · 10-19-2010

ARCHITECTURE

?

architecture |ˈärkiˌtek ch ər|

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

PARADIGMS

Event-Driven

Aspect-Oriented

Declarative

Procedural

Functional

Object-Oriented

PARADIGMS

Event-Driven

Aspect-Oriented

Declarative

Procedural

Functional

Object-Oriented

PARADIGMS

Event-Driven

Aspect-Oriented

Declarative

Procedural

Functional

Object-Oriented

PARADIGMS

Event-Driven

Aspect-Oriented

Declarative

Procedural

Functional

Object-Oriented

BOOTSTRAP / DISPATCH

index.php

/posts

?url=/posts

index.php

/posts

?url=/posts

config/bootstrap.php

config/bootstrap/libraries.php

config/bootstrap/cache.php

config/bootstrap/connections.php

config/bootstrap/action.php

...

index.php

/posts

?url=/posts

config/bootstrap.php

config/bootstrap/libraries.php

config/bootstrap/cache.php

config/bootstrap/connections.php

config/bootstrap/action.php

...

lithium\action\Dispatcher::run(new lithium\action\Request()

)

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 lithium\action\Request()

$_GET $_POST $_SERVER

CONFIGURATION

REQUEST

FILTERS

A.K.A. ASPECT-ORIENTED PROGRAMMING

lithium\action\Dispatcher { //...

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); }}

There are no routes here yet

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);});

config/bootstrap/action.php

lithium\action\Dispatcher { //...

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 app\models\Posts;

app\controllers\PostsController {

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 endend

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 endend

lithium\net\http\Media {

$formats = array( 'html' => array(...), 'json' => array(...), 'xml' => array(...), '...' );}

array('posts' => ...

)

new lithium\action\Response()

new lithium\action\Response()

Controller

View

Dispatcher index.php

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"); // ... }}

class User {

public function somethingUseful() { Logger::info("Something useful is happening"); // ... }}

FALE

Super dumb!!

COUPLING RELEVANCE

Post::applyFilter('save', function($self, $params, $chain) { $entity =& $params['entity'];

if (!$entity->exists()) { $entity->created = time(); } return $chain->next($self, $params, $chain);});

?

Post::applyFilter('save', function($self, $params, $chain) { $entity =& $params['entity'];

if (!$entity->exists()) { $entity->created = time(); } return $chain->next($self, $params, $chain);});

?FALE

class WebService {

protected $_classes = array( 'socket' => 'lithium\net\http\socket\Context', 'request' => 'lithium\net\http\Request', 'response' => 'lithium\net\http\Response' );}

use app\models\Post;use li3_elasticsearch\extensions\data\behavior\Searchable;

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

require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php';require LITHIUM_LIBRARY_PATH . '/lithium/core/StaticObject.php';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 LITHIUM_LIBRARY_PATH . '/lithium/util/String.php';require LITHIUM_LIBRARY_PATH . '/lithium/core/Adaptable.php';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 ....

define('LITHIUM_APP_PATH', dirname(dirname(__DIR__)));define('LITHIUM_LIBRARY_PATH', LITHIUM_APP_PATH . '/../libraries');

Remove whenplugin-izing

config/bootstrap/libraries.php

Make conditional

Libraries::add('my_application', array('default' => true

));

my_awesome_plugin/ config/ bootstrap.php routes.php anything_in_an_app/

Required

Optional

Unless youdisable it

Libraries::add('my_awesome_plugin', array( 'bootstrap' => false));

Happens in the filterwe saw in action.php

DEMO...

top related