Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
THEOF
• Former lead developer, CakePHP• Co-founder & lead developer of  Lithium for ~2 years• Original BostonPHP framework  bake...
• Started as a series of test scripts on early dev builds of PHP 5.3• Released as “Cake3” in July ‘09• Spun off as Lithium...
ARCHITECTURE
Procedural   Object-Oriented
Procedural   Object-Oriented
Aspect-OrientedEvent-Driven                      Procedural               PARADIGMS Declarative                      Funct...
The Fall of Rome           PARADIGM HUBRIS
+   $
Z END F RAMEWORK 1.5
$transport =   new Zend_Mail_Transport_Smtp(smtp.gmail.com, array(  auth       => login,  username   => foo,  password   =...
class Container {    public function getMailTransport() {      return new Zend_Mail_Transport_Smtp(smtp.gmail.com, array( ...
class Container {    protected $parameters = array();    public function __construct(array $parameters = array()) {      $...
$container = new Container(array(  mailer.username => root,  mailer.password => sekr1t,  mailer.class    => Zend_Mail,));$...
class Container extends sfServiceContainer {    static protected $shared = array();    protected function getMailTransport...
sfServiceContainerAutoloader::register();$sc = new sfServiceContainerBuilder();$sc->register(mail.transport, Zend_Mail_Tra...
<?xml version="1.0" ?><container xmlns="http://symfony-project.org/2.0/container">  <parameters>    <parameter key="mailer...
Dependency injection container+ Service container+ Service container builder+ XML
==
mail()
THE MORAL“All problems in computer science can be solved byanother level of indirection. Except for theproblem of too many...
The Guggenheim      Fallingwater    GREAT ARCHITECTURE
WHO WON?
Jet Li’s Fearless        JET LI      AS   HOU YUANJIA
BRUCE LEE
J EET K UNE D OThe Way of the Intercepting Fist
GOALS• Understand a variety of paradigms & their strengths• Respect context when choosing paradigms / techniques• Be simpl...
PROBLEMS• Managing configuration• Staying flexible• Extending internals• Easy things: easy; hard things: possible
CONFIGURATION
webroot/index.phprequire dirname(__DIR__) . /config/bootstrap.php;echo lithiumactionDispatcher::run(    new lithiumactionR...
config/bootstrap.phprequire __DIR__ . /bootstrap/libraries.php;require __DIR__ . /bootstrap/errors.php;require __DIR__ . /...
config/bootstrap/libraries.phpuse lithiumcoreLibraries;Libraries::add(lithium);Libraries::add(app, array(default => true))...
config/bootstrap/cache.phpuse lithiumstorageCache;Cache::config(array(    local => array(adapter => Apc),    distributed =...
config/bootstrap/connections.phpuse lithiumdataConnections;Connections::config(array(    default => array(        type => ...
config/bootstrap/session.phpuse lithiumsecurityAuth;Auth::config(array(    customer => array(        adapter => Form,     ...
MULTIPLE ENVIRONMENTS?use lithiumstorageCache;Cache::config(array(    default => array(        development => array(adapte...
MULTIPLE ENVIRONMENTS?use lithiumstorageCache;Cache::config(array(    default => array(        development => array(adapte...
namespace lithiumnethttp;use lithiumcoreLibraries;class Service extends lithiumcoreObject {    protected $_classes = array...
$service = new   Service(array(    scheme     => https,    host       => web.service.com,    username   => user,    passwo...
$service = new      Service(array(    scheme        => https,    host          => web.service.com,    username      => use...
$service = new Service(array(    scheme   => https,    host     => web.service.com,    username => user,    password => s3...
FLEXIBILITY
HELPERS<?=$this->form->text(email); ?>
HELPERS<?=$this->form->text(email); ?><input type="text" name="email" id="MemberEmail" value="nate.abele@gmail.com" />
HELPERS<?=$this->form->field(name, array(    wrap => array(class => wrapper))); ?>
HELPERS<?=$this->form->field(name, array(    wrap => array(class => wrapper))); ?><div class="wrapper">    <label for="Mem...
HELPERS<?=$this->form->field(name, array(    wrap => array(class => item),    template => <li{:wrap}>{:error}{:label}{:inp...
HELPERS<?=$this->form->field(name, array(    wrap => array(class => item),    template => <li{:wrap}>{:error}{:label}{:inp...
HELPERS$this->form->config(array(templates => array(     field => "<li{:wrap}>{:error}{:label}{:input}</li>")));
HELPERS<input type="text" name="email" id="MemberEmail"        value="nate.abele@gmail.com" />
HELPERS$form = $this->form;$this->form->config(array(attributes => array(   id => function($method, $name, $options) use (...
HELPERS$form = $this->form;$this->form->config(array(attributes => array(   id => function($method, $name, $options) use (...
HELPERS<input type="text" name="email" id="member_email"        value="nate.abele@gmail.com" />
THE MEDIA CLASSclass WeblogController < ActionController::Base  def index    @posts = Post.find :all    respond_to do |for...
THE MEDIA CLASS         !class WeblogController < ActionController::Base  def index    @posts = Post.find :all    respond_...
THE MEDIA CLASS<?php echo $javascript->object($data); ?>
THE MEDIA CLASS       !<?php echo $javascript->object($data); ?>
THE MEDIA CLASS                lithiumnethttpMedia {                     $formats = array(array(                   html =>...
THE MEDIA CLASS                lithiumnethttpMedia {                     $formats = array(array(                   html =>...
THE MEDIA CLASSMedia::type(mobile, array(text/html), array(    view => lithiumtemplateView,    paths => array(        temp...
THE MEDIA CLASSMedia::type(mobile, array(text/html), array(    view => lithiumtemplateView,    paths => array(        temp...
THE MEDIA CLASSMedia::type(ajax, array(text/html), array(    view => lithiumtemplateView,    paths => array(        templa...
THE MEDIA CLASSMedia::type(ajax, array(text/html), array(    view => lithiumtemplateView,    paths => array(        templa...
CONDITIONS?        conditions => array(ajax => true)                         ==               $request->is(ajax)          ...
CONDITIONS?$request->detect(iPhone, array(HTTP_USER_AGENT, /iPhone/));$isiPhone = $request->is(iPhone);$request->detect(cu...
ROUTINGRouter::connect(/{:controller}/{:action}/{:id:[0-9]+}, array(    id => null));new Route(array(    template => /{:co...
ROUTE HANDLERSRouter::connect(/{:user}/{:controller}/{:action});
ROUTE HANDLERSRouter::connect(/{:user}/{:controller}/{:action}, array(), function($request) {    if (!Users::count(array(c...
ROUTE HANDLERSRouter::connect(/{:user}/{:controller}/{:action}, array(), function($request) {    if (!Users::count(array(c...
ROUTE HANDLERSRouter::connect(    /photos/view/{:id:[0-9a-f]{24}}.jpg,    array(),    function($request) {        return n...
MICRO-APPSRouter::connect(/posts.json, array(), function($request) {    return new Response(array(        headers => array...
EXTENSIBILITY
HELPERS     <?=$this->html->*() ?>      lithiumtemplatehelperHtml
HELPERS     <?=$this->html->*() ?>      lithiumtemplatehelperHtml       appextensionshelperHtml
MODELSnamespace appmodels;class Posts extends lithiumdataModel {}
MODELSnamespace appmodels;class Posts extends lithiumdataModel {    protected $_meta = array(        key => custom_id,    ...
MODELSnamespace appmodels;class Posts extends lithiumdataModel {    protected $_meta = array(        key => array(        ...
MODELSPosts::create(array(    title => My first post ever,    body => Wherein I extoll the virtues of Lithium));// ...$pos...
MODELS$post->tags = technology,PHP,news;$post->save();// ...foreach ($post->tags as $tag) {    #FALE}
MODELSnamespace appmodels;class Posts extends lithiumdataModel {    public function tags($entity) {        return explode(...
MODELSnamespace appmodels;class Posts extends lithiumdataModel {    public function tags($entity) {        return explode(...
MODELSnamespace appmodels;class Posts extends lithiumdataModel {    public static function expire() {        return static...
ENTITIES & COLLECTIONS$posts = Posts::findAllBySomeCondition();
ENTITIES & COLLECTIONS$posts = Posts::findAllBySomeCondition();   $posts->first(function($post) {       return $post->publ...
RELATIONSHIPSnamespace appmodels;class Posts extends lithiumdataModel {    public $belongsTo = array(Users);}
RELATIONSHIPSnamespace appmodels;class Posts extends lithiumdataModel {    public $belongsTo = array(Author => array(     ...
RELATIONSHIPSnamespace appmodels;class Posts extends lithiumdataModel {    public $belongsTo = array(Author => array(     ...
RELATIONSHIPSnamespace appmodels;class Posts extends lithiumdataModel {    public $belongsTo = array(Author => array(     ...
NO H AS A ND B ELONGS T O M ANY !!
DOCUMENT DATABASES$post = Posts::create(array(    title => "New post",    body => "Something worthwhile to read",    tags ...
DOCUMENT DATABASES$posts = Posts::all(array(conditions => array(     tags => array(PHP, tech),     author.name => Nate)));
DOCUMENT DATABASES$ages = Users::all(array(    group   => age,    reduce => function(obj, prev) { prev.count++; },    init...
THE QUERY API$query = new Query(array(    type => read,    model => appmodelsPost,    fields => array(Post.title, Post.bod...
FILTERS
$post = Posts::first($id);
Posts::applyFilter(find, function($self, $params, $chain) {    $key = // Make a cache key from $params[options]      if ($...
loggingcachingfind()
loggingcachingfind()
Posts::applyFilter(find, function($self, $params, $chain) {    $key = // Make a cache key from $params[options]      if ($...
THE TALK OF THE TOWN
CAN I USE IT IN PRODUCTION?
GIMMEBAR.COMSean Coates
MAPALONG.COM Chris ShiflettAndrei Zmievski
TOTSY.COMMitch Pirtle
...AND MANY OTHERS
David Coallier                                 • President, PEAR Group                                 • CTO, Echolibre / ...
Helgi Þormar Þorbjörnsson                 • Developer, PEAR Installer                 • PEAR Core Dev, 8 years“It’s the f*...
Fahad Ibnay Heylaal                       • Creator, Croogo CMS“   I believe the future is in Lithium. give    it time to ...
1.0?
SO CLOSE!!
TOMORROW...
0.10
THANKS!!Find me later :  @nateabele  nate.abele@gmail.com  http://nateabele.com/
RESOURCESGetting connected              Learning AOPlithify.me                   bit.ly/aop-designgithub.com/UnionOfRAD   ...
PHOTO CREDITShttp://www.flickr.com/photos/mkebbe/28298461/http://www.flickr.com/photos/josefeliciano/3849557951/http://www...
The Zen of Lithium
The Zen of Lithium
The Zen of Lithium
Upcoming SlideShare
Loading in …5
×

The Zen of Lithium

4,627 views

Published on

"The Zen of Lithium" provides an overview of some of the philosophies behind the Lithium framework

Published in: Technology

The Zen of Lithium

  1. 1. THEOF
  2. 2. • Former lead developer, CakePHP• Co-founder & lead developer of Lithium for ~2 years• Original BostonPHP framework bake-off champ!• Twitter: @nateabele
  3. 3. • Started as a series of test scripts on early dev builds of PHP 5.3• Released as “Cake3” in July ‘09• Spun off as Lithium in October ’09• Based on 5 years’ experience developing a high-adoption web framework
  4. 4. ARCHITECTURE
  5. 5. Procedural Object-Oriented
  6. 6. Procedural Object-Oriented
  7. 7. Aspect-OrientedEvent-Driven Procedural PARADIGMS Declarative Functional Object-Oriented
  8. 8. The Fall of Rome PARADIGM HUBRIS
  9. 9. + $
  10. 10. Z END F RAMEWORK 1.5
  11. 11. $transport = new Zend_Mail_Transport_Smtp(smtp.gmail.com, array( auth => login, username => foo, password => bar, ssl => ssl, port => 465,));$mailer = new Zend_Mail();$mailer->setDefaultTransport($transport);
  12. 12. class Container { public function getMailTransport() { return new Zend_Mail_Transport_Smtp(smtp.gmail.com, array( auth => login, username => root, password => sekr1t, ssl => ssl, port => 465, )); } public function getMailer() { $mailer = new Zend_Mail(); $mailer->setDefaultTransport($this->getMailTransport()); return $mailer; }}
  13. 13. class Container { protected $parameters = array(); public function __construct(array $parameters = array()) { $this->parameters = $parameters; } public function getMailTransport() { return new Zend_Mail_Transport_Smtp(smtp.gmail.com, array( auth => login, username => $this->parameters[mailer.username], password => $this->parameters[mailer.password], ssl => ssl, port => 465, )); } public function getMailer() { $mailer = new Zend_Mail(); $mailer->setDefaultTransport($this->getMailTransport()); return $mailer; }}
  14. 14. $container = new Container(array( mailer.username => root, mailer.password => sekr1t, mailer.class => Zend_Mail,));$mailer = $container->getMailer();
  15. 15. class Container extends sfServiceContainer { static protected $shared = array(); protected function getMailTransportService() { return new Zend_Mail_Transport_Smtp(smtp.gmail.com, array( auth => login, username => $this[mailer.username], password => $this[mailer.password], ssl => ssl, port => 465, )); } protected function getMailerService() { if (isset(self::$shared[mailer])) { return self::$shared[mailer]; } $class = $this[mailer.class]; $mailer = new $class(); $mailer->setDefaultTransport($this->getMailTransportService()); return self::$shared[mailer] = $mailer; }}
  16. 16. sfServiceContainerAutoloader::register();$sc = new sfServiceContainerBuilder();$sc->register(mail.transport, Zend_Mail_Transport_Smtp)-> addArgument(smtp.gmail.com)-> addArgument(array( auth => login, username => %mailer.username%, password => %mailer.password%, ssl => ssl, port => 465, ))->setShared(false);$sc->register(mailer, %mailer.class%)-> addMethodCall(setDefaultTransport, array( new sfServiceReference(mail.transport) ));
  17. 17. <?xml version="1.0" ?><container xmlns="http://symfony-project.org/2.0/container"> <parameters> <parameter key="mailer.username">root</parameter> <parameter key="mailer.password">sekr1t</parameter> <parameter key="mailer.class">Zend_Mail</parameter> </parameters> <services> <service id="mail.transport" class="Zend_Mail_Transport_Smtp" shared="false"> <argument>smtp.gmail.com</argument> <argument type="collection"> <argument key="auth">login</argument> <argument key="username">%mailer.username%</argument> <argument key="password">%mailer.password%</argument> <argument key="ssl">ssl</argument> <argument key="port">465</argument> </argument> </service> <service id="mailer" class="%mailer.class%"> <call method="setDefaultTransport"> <argument type="service" id="mail.transport" /> </call> </service> </services></container>
  18. 18. Dependency injection container+ Service container+ Service container builder+ XML
  19. 19. ==
  20. 20. mail()
  21. 21. THE MORAL“All problems in computer science can be solved byanother level of indirection. Except for theproblem of too many layers of indirection. ” — Butler Lampson / David Wheeler
  22. 22. The Guggenheim Fallingwater GREAT ARCHITECTURE
  23. 23. WHO WON?
  24. 24. Jet Li’s Fearless JET LI AS HOU YUANJIA
  25. 25. BRUCE LEE
  26. 26. J EET K UNE D OThe Way of the Intercepting Fist
  27. 27. GOALS• Understand a variety of paradigms & their strengths• Respect context when choosing paradigms / techniques• Be simple as possible (but no simpler)
  28. 28. PROBLEMS• Managing configuration• Staying flexible• Extending internals• Easy things: easy; hard things: possible
  29. 29. CONFIGURATION
  30. 30. webroot/index.phprequire dirname(__DIR__) . /config/bootstrap.php;echo lithiumactionDispatcher::run( new lithiumactionRequest());
  31. 31. config/bootstrap.phprequire __DIR__ . /bootstrap/libraries.php;require __DIR__ . /bootstrap/errors.php;require __DIR__ . /bootstrap/cache.php;require __DIR__ . /bootstrap/connections.php;require __DIR__ . /bootstrap/action.php;require __DIR__ . /bootstrap/session.php;require __DIR__ . /bootstrap/g11n.php;require __DIR__ . /bootstrap/media.php;require __DIR__ . /bootstrap/console.php;
  32. 32. config/bootstrap/libraries.phpuse lithiumcoreLibraries;Libraries::add(lithium);Libraries::add(app, array(default => true));Libraries::add(li3_docs);
  33. 33. config/bootstrap/cache.phpuse lithiumstorageCache;Cache::config(array( local => array(adapter => Apc), distributed => array( adapter => Memcache, host => 127.0.0.1:11211 ), default => array(adapter => File)));
  34. 34. config/bootstrap/connections.phpuse lithiumdataConnections;Connections::config(array( default => array( type => MongoDb, database => my_mongo_db ), legacy => array( type => database, adapter => MySql, login => bobbytables, password => s3kr1t, database => my_mysql_db )));
  35. 35. config/bootstrap/session.phpuse lithiumsecurityAuth;Auth::config(array( customer => array( adapter => Form, model => Customers, fields => array(email, password) ), administrator => array( adapter => Http, method => digest, users => array(nate => li3) )));
  36. 36. MULTIPLE ENVIRONMENTS?use lithiumstorageCache;Cache::config(array( default => array( development => array(adapter => Apc), production => array( adapter => Memcache, host => 127.0.0.1:1121 ) )));
  37. 37. MULTIPLE ENVIRONMENTS?use lithiumstorageCache;Cache::config(array( default => array( development => array(adapter => Apc), production => array( adapter => Memcache, host => 127.0.0.1:1121 ) )));
  38. 38. namespace lithiumnethttp;use lithiumcoreLibraries;class Service extends lithiumcoreObject { protected $_classes = array( media => lithiumnethttpMedia, request => lithiumnethttpRequest, response => lithiumnethttpResponse, ); public function __construct(array $config = array()) { $defaults = array( scheme => http, host => localhost, // ... ); parent::__construct($config + $defaults); } protected function _init() { // ... }}
  39. 39. $service = new Service(array( scheme => https, host => web.service.com, username => user, password => s3kr1t));
  40. 40. $service = new Service(array( scheme => https, host => web.service.com, username => user, password => s3kr1t));{ “lithiumnethttpService”: { “scheme”: “https”, “host”: “web.service.com”, “username”: “user”, “password”: “s3kr1t” }}
  41. 41. $service = new Service(array( scheme => https, host => web.service.com, username => user, password => s3kr1t, classes => array( request => mycustomRequest )));
  42. 42. FLEXIBILITY
  43. 43. HELPERS<?=$this->form->text(email); ?>
  44. 44. HELPERS<?=$this->form->text(email); ?><input type="text" name="email" id="MemberEmail" value="nate.abele@gmail.com" />
  45. 45. HELPERS<?=$this->form->field(name, array( wrap => array(class => wrapper))); ?>
  46. 46. HELPERS<?=$this->form->field(name, array( wrap => array(class => wrapper))); ?><div class="wrapper"> <label for="MemberName">Name</label> <input type="text" name="name" id="MemberName" /> <div class="error">You dont have a name?</div></div>
  47. 47. HELPERS<?=$this->form->field(name, array( wrap => array(class => item), template => <li{:wrap}>{:error}{:label}{:input}</li>)); ?>
  48. 48. HELPERS<?=$this->form->field(name, array( wrap => array(class => item), template => <li{:wrap}>{:error}{:label}{:input}</li>)); ?><li class="item"> <div class="error">You dont have a name?</div> <label for="MemberName">Name</label> <input type="text" name="name" id="MemberName" /></div>
  49. 49. HELPERS$this->form->config(array(templates => array( field => "<li{:wrap}>{:error}{:label}{:input}</li>")));
  50. 50. HELPERS<input type="text" name="email" id="MemberEmail" value="nate.abele@gmail.com" />
  51. 51. HELPERS$form = $this->form;$this->form->config(array(attributes => array( id => function($method, $name, $options) use (&$form) { if ($method != text && $method != select) { return; } $model = null; if ($binding = $form->binding()) { $model = basename(str_replace(, /, $binding->model())) . _; } return Inflector::underscore($model . $name); })));
  52. 52. HELPERS$form = $this->form;$this->form->config(array(attributes => array( id => function($method, $name, $options) use (&$form) { if ($method != text && $method != select) { return; } $model = null; if ($binding = $form->binding()) { $model = basename(str_replace(, /, $binding->model())) . _; } return Inflector::underscore($model . $name); })));
  53. 53. HELPERS<input type="text" name="email" id="member_email" value="nate.abele@gmail.com" />
  54. 54. THE MEDIA CLASSclass 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
  55. 55. THE MEDIA CLASS !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
  56. 56. THE MEDIA CLASS<?php echo $javascript->object($data); ?>
  57. 57. THE MEDIA CLASS !<?php echo $javascript->object($data); ?>
  58. 58. THE MEDIA CLASS lithiumnethttpMedia { $formats = array(array( html => array(...), posts => ... json => array(...),) xml => array(...), ... ); }
  59. 59. THE MEDIA CLASS lithiumnethttpMedia { $formats = array(array( html => array(...), posts => ... json => array(...),) xml => array(...), ... ); }
  60. 60. THE MEDIA CLASSMedia::type(mobile, array(text/html), array( view => lithiumtemplateView, paths => array( template => array( {:library}/views/{:controller}/{:template}.mobile.php, {:library}/views/{:controller}/{:template}.html.php, ), layout => array( {:library}/views/layouts/{:layout}.mobile.php, {:library}/views/layouts/{:layout}.html.php, ), element => array( {:library}/views/elements/{:template}.mobile.php {:library}/views/elements/{:template}.html.php ) ), conditions => array(mobile => true)));
  61. 61. THE MEDIA CLASSMedia::type(mobile, array(text/html), array( view => lithiumtemplateView, paths => array( template => array( {:library}/views/{:controller}/{:template}.mobile.php, {:library}/views/{:controller}/{:template}.html.php, ), layout => array( {:library}/views/layouts/{:layout}.mobile.php, {:library}/views/layouts/{:layout}.html.php, ), element => array( {:library}/views/elements/{:template}.mobile.php {:library}/views/elements/{:template}.html.php ) ), conditions => array(mobile => true)));
  62. 62. THE MEDIA CLASSMedia::type(ajax, array(text/html), array( view => lithiumtemplateView, paths => array( template => array( {:library}/views/{:controller}/{:template}.ajax.php, {:library}/views/{:controller}/{:template}.html.php, ), layout => false, element => array( {:library}/views/elements/{:template}.ajax.php {:library}/views/elements/{:template}.html.php ) ), conditions => array(ajax => true)));
  63. 63. THE MEDIA CLASSMedia::type(ajax, array(text/html), array( view => lithiumtemplateView, paths => array( template => array( {:library}/views/{:controller}/{:template}.ajax.php, {:library}/views/{:controller}/{:template}.html.php, ), layout => false, element => array( {:library}/views/elements/{:template}.ajax.php {:library}/views/elements/{:template}.html.php ) ), conditions => array(ajax => true)));
  64. 64. CONDITIONS? conditions => array(ajax => true) == $request->is(ajax) == $_SERVER[HTTP_X_REQUESTED_WITH] = XMLHttpRequest
  65. 65. CONDITIONS?$request->detect(iPhone, array(HTTP_USER_AGENT, /iPhone/));$isiPhone = $request->is(iPhone);$request->detect(custom, function($request) { if ($value = $request->env("HTTP_WHATEVER")) { // Do something with $value } return false;});
  66. 66. ROUTINGRouter::connect(/{:controller}/{:action}/{:id:[0-9]+}, array( id => null));new Route(array( template => /{:controller}/{:action}/{:id:[0-9]+}, pattern => @^(?:/(?P[^/]+))(?:/(?P[^/]+)?)?(?:/(?P[0-9]+)?)?$@, params => array(id => null, action => index), // ... subPatterns => array(id => [0-9]+), persist => array(controller)));Router::connect(new CustomRoute($params));
  67. 67. ROUTE HANDLERSRouter::connect(/{:user}/{:controller}/{:action});
  68. 68. ROUTE HANDLERSRouter::connect(/{:user}/{:controller}/{:action}, array(), function($request) { if (!Users::count(array(conditions => array(user => $request->user)))) { return false; } return $request;});
  69. 69. ROUTE HANDLERSRouter::connect(/{:user}/{:controller}/{:action}, array(), function($request) { if (!Users::count(array(conditions => array(user => $request->user)))) { return false; } return $request;});Router::connect(/, array(), function($request) { if (Session::read(user)) { $location = Accounts::index; } else { $location = Users::add; } return new Response(array(status => 302, location => $location));});
  70. 70. ROUTE HANDLERSRouter::connect( /photos/view/{:id:[0-9a-f]{24}}.jpg, array(), function($request) { return new Response(array( headers => array(Content-type => image/jpeg), body => Photos::first($request->id)->file->getBytes() )); });
  71. 71. MICRO-APPSRouter::connect(/posts.json, array(), function($request) { return new Response(array( headers => array(Content-type => application/json), body => Posts::all()->to(json) ));});Router::connect(/posts/{:id}.json, array(), function($request) { return new Response(array( headers => array(Content-type => application/json), body => Posts::first($request->id)->to(json) ));});
  72. 72. EXTENSIBILITY
  73. 73. HELPERS <?=$this->html->*() ?> lithiumtemplatehelperHtml
  74. 74. HELPERS <?=$this->html->*() ?> lithiumtemplatehelperHtml appextensionshelperHtml
  75. 75. MODELSnamespace appmodels;class Posts extends lithiumdataModel {}
  76. 76. MODELSnamespace appmodels;class Posts extends lithiumdataModel { protected $_meta = array( key => custom_id, source => custom_posts_table connection => legacy_mysql_db );}
  77. 77. MODELSnamespace appmodels;class Posts extends lithiumdataModel { protected $_meta = array( key => array( custom_id, other_custom_id ) );}
  78. 78. MODELSPosts::create(array( title => My first post ever, body => Wherein I extoll the virtues of Lithium));// ...$post->save();
  79. 79. MODELS$post->tags = technology,PHP,news;$post->save();// ...foreach ($post->tags as $tag) { #FALE}
  80. 80. MODELSnamespace appmodels;class Posts extends lithiumdataModel { public function tags($entity) { return explode(,, $entity->tags); }}foreach ($post->tags() as $tag) { // ...}
  81. 81. MODELSnamespace appmodels;class Posts extends lithiumdataModel { public function tags($entity) { return explode(,, $entity->tags); }}foreach ($post->tags() as $tag) { // ...}
  82. 82. MODELSnamespace appmodels;class Posts extends lithiumdataModel { public static function expire() { return static::update( array(expired => true), array(updated => array( <= => strtotime(3 months ago) )) ); }}$didItWork = Posts::expire();
  83. 83. ENTITIES & COLLECTIONS$posts = Posts::findAllBySomeCondition();
  84. 84. ENTITIES & COLLECTIONS$posts = Posts::findAllBySomeCondition(); $posts->first(function($post) { return $post->published == true; }); $posts->each(function($post) { return $post->counter++; }); $ids = $posts->map(function($post) { return $post->id; });
  85. 85. RELATIONSHIPSnamespace appmodels;class Posts extends lithiumdataModel { public $belongsTo = array(Users);}
  86. 86. RELATIONSHIPSnamespace appmodels;class Posts extends lithiumdataModel { public $belongsTo = array(Author => array( class => Users ));}
  87. 87. RELATIONSHIPSnamespace appmodels;class Posts extends lithiumdataModel { public $belongsTo = array(Author => array( class => Users, conditions => array(active => true), key => author_id ));}
  88. 88. RELATIONSHIPSnamespace appmodels;class Posts extends lithiumdataModel { public $belongsTo = array(Author => array( class => Users, conditions => array(active => true), key => array( author_id => id, other_key => other_id ) ));}
  89. 89. NO H AS A ND B ELONGS T O M ANY !!
  90. 90. DOCUMENT DATABASES$post = Posts::create(array( title => "New post", body => "Something worthwhile to read", tags => array(PHP, tech), author => array(name => Nate)));
  91. 91. DOCUMENT DATABASES$posts = Posts::all(array(conditions => array( tags => array(PHP, tech), author.name => Nate)));
  92. 92. DOCUMENT DATABASES$ages = Users::all(array( group => age, reduce => function(obj, prev) { prev.count++; }, initial => array(count => 0)));
  93. 93. THE QUERY API$query = new Query(array( type => read, model => appmodelsPost, fields => array(Post.title, Post.body), conditions => array(Post.id => new Query(array( type => read, fields => array(post_id), model => appmodelsTagging, conditions => array(Tag.name => array(foo, bar, baz)), )))));
  94. 94. FILTERS
  95. 95. $post = Posts::first($id);
  96. 96. Posts::applyFilter(find, function($self, $params, $chain) { $key = // Make a cache key from $params[options] if ($result = Cache::read(default, $key)) { return $result; } $result = $chain->next($self, $params, $chain); Cache::write(default, $key, $result); return $result;});
  97. 97. loggingcachingfind()
  98. 98. loggingcachingfind()
  99. 99. Posts::applyFilter(find, function($self, $params, $chain) { $key = // Make a cache key from $params[options] if ($result = Cache::read(default, $key)) { return $result; } $result = $chain->next($self, $params, $chain); Cache::write(default, $key, $result); return $result;});
  100. 100. THE TALK OF THE TOWN
  101. 101. CAN I USE IT IN PRODUCTION?
  102. 102. GIMMEBAR.COMSean Coates
  103. 103. MAPALONG.COM Chris ShiflettAndrei Zmievski
  104. 104. TOTSY.COMMitch Pirtle
  105. 105. ...AND MANY OTHERS
  106. 106. David Coallier • President, PEAR Group • CTO, Echolibre / Orchestra.io“ After looking at Lithium I’ve come to realize how far ahead it is compared to other frameworks from a technologists point of view. ”
  107. 107. Helgi Þormar Þorbjörnsson • Developer, PEAR Installer • PEAR Core Dev, 8 years“It’s the f*****g epiphany of modern! ”
  108. 108. Fahad Ibnay Heylaal • Creator, Croogo CMS“ I believe the future is in Lithium. give it time to grow, and the developers behind it are awesome. ”
  109. 109. 1.0?
  110. 110. SO CLOSE!!
  111. 111. TOMORROW...
  112. 112. 0.10
  113. 113. THANKS!!Find me later : @nateabele nate.abele@gmail.com http://nateabele.com/
  114. 114. RESOURCESGetting connected Learning AOPlithify.me bit.ly/aop-designgithub.com/UnionOfRAD bit.ly/aop-gwoo#li3 on irc.freenode.net bit.ly/aop-li3@UnionOfRAD bit.ly/aop-oop Talks bit.ly/mwop-aopslideshare.net/nateabele
  115. 115. PHOTO CREDITShttp://www.flickr.com/photos/mkebbe/28298461/http://www.flickr.com/photos/josefeliciano/3849557951/http://www.flickr.com/photos/cku/1386908692/http://www.flickr.com/photos/macten/4611148426/http://www.rustybrick.com/prototype-js-vs-jquery-comparison.htmlhttp://www.flickr.com/photos/cadsonline/4321530819/http://www.flickr.com/photos/maiptitfleur/4942829255/

×