SlideShare a Scribd company logo
Lithium (#li3)
The framework with the best of both worlds
Richard McIntyre: @mackstar

★ Lithium core team

★ Freelancer - Leeds/Manchester

★ Most recently at BBC, Mamas & Papas, UOR

★ Engineer on BBC Olympics App

★ Lived in Japan 15 years

★ Done PHP for donkeys
Lithium Best
Frameworks
Lithium Best
I’ve seen it
✦ Symfony 2        ✦ Merb

✦ Zend Framework   ✦ Sinatra

✦ CakePHP          ✦ Spring

✦ Code Igniter     ✦ Stripes (Java)

✦ Drupal 6&7       ✦ Django
                       Wordpress
✦ Silex
                   ✦




✦ Rails
Lithium Best
many
frameworks
are
like
this
Each software solution should be in proportion to
the problem being solved.
Each software solution should be in proportion to
the problem being solved.

                            -some lazy bugger
Each software solution should be in proportion to
the problem being solved.

                            -some lazy bugger
                                           me
<?php

use BehatMinkExtensionContextMinkContext;

class FeatureContext extends MinkContext
{
   /**
    * @Then /^I wait for the suggestion box to appear$/
    */
   public function myNameHasAMeaninglessExistance()
   {
      $this->getSession()->wait(5000, "$('.suggestions-results').children().length >
0");
   }
}
All problems in computer science can be solved
by another level of indirection. Except for the
problem of too many layers of indirection.

                 Butler Lampson, David Wheeler
Code Sexy-ness
There’s nothing like the look of beautiful Ruby code in the morning.
Gracefully colored by TextMate and rendered in Bitstream Vera pt 12.
@dhh
Developer Happy-ness
Any fool can write code that a computer can understand. Good
programmers write code that humans can understand.
                                                        –Martin Fowler
Light Footprint
Light Footprint
Looking for a hackers Framework?




Light Footprint
Fast, Flexible and Rad
World 1




Full Stack Framework
   Convention Over Configuration
github.com/UnionOfRad/framework
The Photo Blog Tutorial
   github.com/nateabele/photoblog
Model
namespace photoblogmodels;

class Photos extends lithiumdataModel {

    public $validates = array();

    protected $_meta = array('source' => 'fs.files');

    public function save($entity, $data = null, array $options = array()) {
      if ($data) {
        $entity->set($data);
      }
      if ($entity->tags && !is_array($entity->tags)) {
        $entity->tags = array_map('trim', explode(',', $entity->tags));
      }
      return parent::save($entity, null, $options);
    }
}
Model
namespace photoblogmodels;

class Photos extends lithiumdataModel {

    public $validates = array();

    protected $_meta = array('source' => 'fs.files');

    public function save($entity, $data = null, array $options = array()) {
      if ($data) {
        $entity->set($data);
      }
      if ($entity->tags && !is_array($entity->tags)) {
        $entity->tags = array_map('trim', explode(',', $entity->tags));
      }
      return parent::save($entity, null, $options);
    }
}
Model
namespace photoblogmodels;

class Photos extends lithiumdataModel {

    public $validates = array();

    protected $_meta = array('source' => 'fs.files');

    public function save($entity, $data = null, array $options = array()) {
      if ($data) {
        $entity->set($data);
      }
      if ($entity->tags && !is_array($entity->tags)) {
        $entity->tags = array_map('trim', explode(',', $entity->tags));
      }
      return parent::save($entity, null, $options);
    }
}
Views

<?=$this->form->create($photo, array('type' => 'file')); ?>
 <?=$this->form->field('title'); ?>
 <?=$this->form->field('description'); ?>
 <?php if (!$photo->exists()): ?>
  <?=$this->form->field('file', array('type' => 'file')); ?>
 <?php endif; ?>
 <?=$this->form->field('tags', array('label' =>
                             'Add tags separated by commas')); ?>
 <?=$this->form->submit('Save'); ?>
<?=$this->form->end(); ?>
Views

<?=$this->form->create($photo, array('type' => 'file')); ?>
 <?=$this->form->field('title'); ?>
 <?=$this->form->field('description'); ?>
 <?php if (!$photo->exists()): ?>
  <?=$this->form->field('file', array('type' => 'file')); ?>
 <?php endif; ?>
 <?=$this->form->field('tags', array('label' =>
                             'Add tags separated by commas')); ?>
 <?=$this->form->submit('Save'); ?>
<?=$this->form->end(); ?>
Views

<?=$this->form->create($photo, array('type' => 'file')); ?>
 <?=$this->form->field('title'); ?>
 <?=$this->form->field('description'); ?>
 <?php if (!$photo->exists()): ?>
  <?=$this->form->field('file', array('type' => 'file')); ?>
 <?php endif; ?>
 <?=$this->form->field('tags', array('label' =>
                             'Add tags separated by commas')); ?>
 <?=$this->form->submit('Save'); ?>
<?=$this->form->end(); ?>
<h1>
 <?=$this->title($photo->title); ?>
 <em>[
   <?=$this->html->link(
               'edit', array('Photos::edit', 'id' => $photo->_id)
          ); ?> ]</em>
</h1>

<p><?=$photo->description; ?></p>

<?php if ($photo->tags): ?>
 Tags:
 <?php foreach ($photo->tags as $tag): ?>
  <?=$this->html->link(
      $tag, array('Photos::index', 'args' => array($tag))
   ); ?>
 <?php endforeach; ?>
<?php endif; ?>

<?=$this->html->image(
      "/photos/view/{$photo->_id}.jpeg", array(
         'alt' => $photo->title, 'width' => "100%"
      )
); ?>
<h1>
 <?=$this->title($photo->title); ?>
 <em>[
   <?=$this->html->link(
               'edit', array('Photos::edit', 'id' => $photo->_id)
          ); ?> ]</em>
</h1>

<p><?=$photo->description; ?></p>

<?php if ($photo->tags): ?>
 Tags:
 <?php foreach ($photo->tags as $tag): ?>
  <?=$this->html->link(
      $tag, array('Photos::index', 'args' => array($tag))
   ); ?>
 <?php endforeach; ?>
<?php endif; ?>

<?=$this->html->image(
      "/photos/view/{$photo->_id}.jpeg", array(
         'alt' => $photo->title, 'width' => "100%"
      )
); ?>
<h1>
 <?=$this->title($photo->title); ?>
 <em>[
   <?=$this->html->link(
               'edit', array('Photos::edit', 'id' => $photo->_id)
          ); ?> ]</em>
</h1>

<p><?=$photo->description; ?></p>

<?php if ($photo->tags): ?>
 Tags:
 <?php foreach ($photo->tags as $tag): ?>
  <?=$this->html->link(
      $tag, array('Photos::index', 'args' => array($tag))
   ); ?>
 <?php endforeach; ?>
<?php endif; ?>

<?=$this->html->image(
      "/photos/view/{$photo->_id}.jpeg", array(
         'alt' => $photo->title, 'width' => "100%"
      )
); ?>
Controller

namespace photoblogcontrollers;

use photoblogmodelsPhotos;
use li3_geoextensionsGeocoder;

class PhotosController extends lithiumactionController {

 public function index($tags = null) {
   $conditions = $tags ? compact('tags') : array();
   $photos = Photos::all(compact('conditions'));
   return compact('photos');
 }

 public function view() {
   $photo = Photos::first($this->request->id);
   return compact('photo');
 }
Controller

namespace photoblogcontrollers;

use photoblogmodelsPhotos;
use li3_geoextensionsGeocoder;

class PhotosController extends lithiumactionController {

 public function index($tags = null) {
   $conditions = $tags ? compact('tags') : array();
   $photos = Photos::all(compact('conditions'));
   return compact('photos');
 }

 public function view() {
   $photo = Photos::first($this->request->id);
   return compact('photo');
 }
Controller

namespace photoblogcontrollers;

use photoblogmodelsPhotos;
use li3_geoextensionsGeocoder;

class PhotosController extends lithiumactionController {

 public function index($tags = null) {
   $conditions = $tags ? compact('tags') : array();
   $photos = Photos::all(compact('conditions'));
   return compact('photos');
 }

 public function view() {
   $photo = Photos::first($this->request->id);
   return compact('photo');
 }
public function near($place = null) {
 $this->_render['template'] = 'index';
 $coords = Geocoder::find('google', $place);

    $photos = Photos::within(array($coords, $coords), array('limit' => 1));
    return compact('photos');
}

public function add() {
  $photo = Photos::create();
  if (($this->request->data) && $photo->save($this->request->data)) {
    $this->redirect(array('Photos::view', 'id' => $photo->_id));
  }
  $this->_render['template'] = 'edit';
  return compact('photo');
}

public function edit() {
  $photo = Photos::find($this->request->id);
  if (!$photo) {
    $this->redirect('Photos::index');
  }
  if (($this->request->data) && $photo->save($this->request->data)) {
    $this->redirect(array('Photos::view', 'id' => $photo->_id));
  }
  return compact('photo');
}
public function near($place = null) {
 $this->_render['template'] = 'index';
 $coords = Geocoder::find('google', $place);

    $photos = Photos::within(array($coords, $coords), array('limit' => 1));
    return compact('photos');
}

public function add() {
  $photo = Photos::create();
                                              Geo Location
  if (($this->request->data) && $photo->save($this->request->data)) {
    $this->redirect(array('Photos::view', 'id' => $photo->_id));
  }
  $this->_render['template'] = 'edit';
  return compact('photo');
}

public function edit() {
  $photo = Photos::find($this->request->id);
  if (!$photo) {
    $this->redirect('Photos::index');
  }
  if (($this->request->data) && $photo->save($this->request->data)) {
    $this->redirect(array('Photos::view', 'id' => $photo->_id));
  }
  return compact('photo');
}
Routes
use   lithiumnethttpRouter;
use   lithiumcoreEnvironment;
use   lithiumactionResponse;
use   photoblogmodelsPhotos;

Router::connect('/photos/view/{:id:[0-9a-f]{24}}.jpeg', array(), function($request) {
  return new Response(array(
    'headers' => array('Content-type' => 'image/jpeg'),
    'body' => Photos::first($request->id)->file->getBytes()
  ));
});

/**
 * Connect the testing routes.
 */
if (!Environment::is('production')) {
  Router::connect('/test/{:args}', array('controller' => 'lithiumtestController'));
  Router::connect('/test', array('controller' => 'lithiumtestController'));
}
Routes
use   lithiumnethttpRouter;
use   lithiumcoreEnvironment;
use   lithiumactionResponse;
use   photoblogmodelsPhotos;

Router::connect('/photos/view/{:id:[0-9a-f]{24}}.jpeg', array(), function($request) {
  return new Response(array(
    'headers' => array('Content-type' => 'image/jpeg'),
    'body' => Photos::first($request->id)->file->getBytes()
  ));
});

/**
 * Connect the testing routes.
                                                                               By-Passes
 */
if (!Environment::is('production')) {                                       the framework
  Router::connect('/test/{:args}', array('controller' => 'lithiumtestController'));
  Router::connect('/test', array('controller' => 'lithiumtestController'));
}
Routes
use   lithiumnethttpRouter;
use   lithiumcoreEnvironment;
use   lithiumactionResponse;
use
        It’s PHP you can
      photoblogmodelsPhotos;

Router::connect('/photos/view/{:id:[0-9a-f]{24}}.jpeg', array(), function($request) {
 return new Response(array( you
            doarray('Content-type' => 'image/jpeg'),
                  what
   'headers' =>
                   want
   'body' => Photos::first($request->id)->file->getBytes()
 ));
});

/**
 * Connect the testing routes.
 */
if (!Environment::is('production')) {
  Router::connect('/test/{:args}', array('controller' => 'lithiumtestController'));
  Router::connect('/test', array('controller' => 'lithiumtestController'));
}
Structure
Features
✦ Full stack MVC          ✦ Object based record-
                            sets
✦ Logger
                          ✦ Command Line
✦ Caching                   Framework

✦ Sessions/Cookies        ✦ Authentication

✦ Full templating suite   ✦ Validator

✦ Integrated TDD suite    ✦ Http Services
Boring
Now for some fun!
World 2




Kick-ass de-coupled hacker happy framework
Are you a
slave to your
framework?
Lithium Best
Lithium Best
Flexible, transparent boostrap process
Database

namespace models;

class Posts extends lithiumdataModel {

}
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;
Libraries::add('lithium');

use lithiumdataConnections;
Connections::add('default', array(
  'type' => 'MongoDb',
  'database' => 'phpnw',
  'host' => 'localhost'
));

Libraries::add('models', array('path' => __DIR__ . '/models'));

use modelsPosts;
$posts = Posts::create(array('title' => 'Hi Guys'));
$posts->save();
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;
Libraries::add('lithium');                  Simple lithium setup
use lithiumdataConnections;
Connections::add('default', array(
  'type' => 'MongoDb',
  'database' => 'phpnw',
  'host' => 'localhost'
));

Libraries::add('models', array('path' => __DIR__ . '/models'));

use modelsPosts;
$posts = Posts::create(array('title' => 'Hi Guys'));
$posts->save();
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;
Libraries::add('lithium');

use lithiumdataConnections;
Connections::add('default', array(
  'type' => 'MongoDb',
  'database' => 'phpnw',                       DB Config
  'host' => 'localhost'
));

Libraries::add('models', array('path' => __DIR__ . '/models'));

use modelsPosts;
$posts = Posts::create(array('title' => 'Hi Guys'));
$posts->save();
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;
Libraries::add('lithium');

use lithiumdataConnections;
Connections::add('default', array(
  'type' => 'MongoDb',
  'database' => 'phpnw',
  'host' => 'localhost'
));                                         Add models ‘app’
Libraries::add('models', array('path' => __DIR__ . '/models'));

use modelsPosts;
$posts = Posts::create(array('title' => 'Hi Guys'));
$posts->save();
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;
Libraries::add('lithium');

use lithiumdataConnections;
Connections::add('default', array(
  'type' => 'MongoDb',
  'database' => 'phpnw',
  'host' => 'localhost'
));

        DB Save
Libraries::add('models', array('path' => __DIR__ . '/models'));

use modelsPosts;
$posts = Posts::create(array('title' => 'Hi Guys'));
$posts->save();
Routes

define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;
Libraries::add('lithium');

use lithiumnethttpRouter;
use lithiumactionRequest;

$request = new Request();
$router = new Router();

$router->connect('/cool-root', array('controller' => 'Yea'));
$router->connect('/cool-root/{:application_id:[0-9]{1}}', array('controller' => 'Yea'));
$router->parse($request);

echo Router::match('Yea::index');
echo Router::match(array('Yea::index', 'application_id' => 1));
Routes

define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;
Libraries::add('lithium');

use lithiumnethttpRouter;
use lithiumactionRequest;

$request = new Request();
$router = new Router();

$router->connect('/cool-root', array('controller' => 'Yea'));
$router->connect('/cool-root/{:application_id:[0-9]{1}}', array('controller' => 'Yea'));
$router->parse($request);

echo Router::match('Yea::index');
echo Router::match(array('Yea::index', 'application_id' => 1));
Routes

define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;
Libraries::add('lithium');

use lithiumnethttpRouter;
use lithiumactionRequest;

$request = new Request();
$router = new Router();

$router->connect('/cool-root', array('controller' => 'Yea'));
$router->connect('/cool-root/{:application_id:[0-9]{1}}', array('controller' => 'Yea'));
$router->parse($request);

echo Router::match('Yea::index');
echo Router::match(array('Yea::index', 'application_id' => 1));
Routes

define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;
Libraries::add('lithium');

use lithiumnethttpRouter;
use lithiumactionRequest;

$request = new Request();
$router = new Router();

$router->connect('/cool-root', array('controller' => 'Yea'));
$router->connect('/cool-root/{:application_id:[0-9]{1}}', array('controller' => 'Yea'));
$router->parse($request);

echo Router::match('Yea::index');
echo Router::match(array('Yea::index', 'application_id' => 1));
Lithium Best
/cool-root/4
/cool-root/4

$router->connect('/cool-root/{:application_id:[0-9]{1}}',
                    array('controller' => 'Yea'));
/cool-root/4

$router->connect('/cool-root/{:application_id:[0-9]{1}}',
                    array('controller' => 'Yea'));



  object(lithiumactionRequest)[1]
   public 'url' => string '/cool-root/4' (length=12)
   public 'params' =>
    array (size=3)
      'application_id' => string '4' (length=1)
      'controller' => string 'Yea' (length=3)
      'action' => string 'index' (length=5)
Adaptable Classes

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

require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/Libraries.php';
require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/Object.php';
require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/StaticObject.php';
require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/Environment.php';
require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/Adaptable.php';

use lithiumcoreAdaptable;

class Email extends Adaptable{

    protected static $_configurations = array();
    protected static $_adapters = 'emails';

}
Adaptable Classes

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

require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/Libraries.php';
require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/Object.php';
require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/StaticObject.php';
require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/Environment.php';
require   LITHIUM_LIBRARY_PATH     .   '/lithium/core/Adaptable.php';

use lithiumcoreAdaptable;

class Email extends Adaptable{

    protected static $_configurations = array();
    protected static $_adapters = 'emails';

}
namespace adapters;
use lithiumcoreLibraries;
Libraries::add('lithium');                      class EmailTest
Libraries::add('adapters',                      {
     array('path' => __DIR__ . '/adapters'));     public function send() {
Libraries::paths(                                   echo 'email test send';
     array('emails' => array(                     }
        '{:library}{:name}')));                }
Email::config(array(
  'development' => array(
    'adapter' => 'EmailReal'
  ),                                            namespace adapters;
  'test' => array(
    'adapter' => 'EmailTest'                    class EmailReal
  ),                                            {
));                                               public function send() {
                                                    echo 'email real send';
use lithiumcoreEnvironment;                     }
                                                }
Environment::set('test');
$env = Environment::get();

Email::adapter($env)->send();
namespace adapters;
use lithiumcoreLibraries;
Libraries::add('lithium');                      class EmailTest
Libraries::add('adapters',                      {
     array('path' => __DIR__ . '/adapters'));     public function send() {
Libraries::paths(                                   echo 'email test send';
     array('emails' => array(                     }
        '{:library}{:name}')));                }
Email::config(array(
  'development' => array(
    'adapter' => 'EmailReal'
  ),                                            namespace adapters;
  'test' => array(
    'adapter' => 'EmailTest'                    class EmailReal
  ),                                            {
));                                               public function send() {
                                                    echo 'email real send';
use lithiumcoreEnvironment;                     }
                                                }
Environment::set('test');
$env = Environment::get();

Email::adapter($env)->send();
namespace adapters;
use lithiumcoreLibraries;
Libraries::add('lithium');                      class EmailTest
Libraries::add('adapters',                      {
     array('path' => __DIR__ . '/adapters'));     public function send() {
Libraries::paths(                                   echo 'email test send';
     array('emails' => array(                     }
        '{:library}{:name}')));                }
Email::config(array(
  'development' => array(
    'adapter' => 'EmailReal'
  ),                                            namespace adapters;
  'test' => array(
    'adapter' => 'EmailTest'                    class EmailReal
  ),                                            {
));                                               public function send() {
                                                    echo 'email real send';
use lithiumcoreEnvironment;                     }
                                                }
Environment::set('test');
$env = Environment::get();

Email::adapter($env)->send();
namespace adapters;
use lithiumcoreLibraries;
Libraries::add('lithium');                      class EmailTest
Libraries::add('adapters',                      {
     array('path' => __DIR__ . '/adapters'));     public function send() {
Libraries::paths(                                   echo 'email test send';
     array('emails' => array(                     }
        '{:library}{:name}')));                }
Email::config(array(
  'development' => array(
    'adapter' => 'EmailReal'
  ),                                            namespace adapters;
  'test' => array(
    'adapter' => 'EmailTest'                    class EmailReal
  ),                                            {
));                                               public function send() {
                                                    echo 'email real send';
use lithiumcoreEnvironment;                     }
                                                }
Environment::set('test');
$env = Environment::get();

Email::adapter($env)->send();
Environment::set('development');

class EmailAnother extends Adaptable{             Already
    protected static $_configurations = array();
    protected static $_adapters = 'emails';
                                                  Environment
    public static function send() {
      static::adapter('default')->send();
                                                  Aware
    }

}

EmailAnother::config(array(
  'default' => array(
    'test' => array (
      'adapter' => 'EmailTest'
    ),
    'development' => array(
      'adapter' => 'EmailReal'
    ),
  )
));

EmailAnother::send();
Environment::set('development');

class EmailAnother extends Adaptable{             Already
    protected static $_configurations = array();
    protected static $_adapters = 'emails';
                                                  Environment
    public static function send() {
      static::adapter('default')->send();
                                                  Aware
    }

}

EmailAnother::config(array(
  'default' => array(
    'test' => array (
      'adapter' => 'EmailTest'
    ),
    'development' => array(
      'adapter' => 'EmailReal'
    ),
  )
));

EmailAnother::send();
Environment::set('development');

class EmailAnother extends Adaptable{             Already
    protected static $_configurations = array();
    protected static $_adapters = 'emails';
                                                  Environment
    public static function send() {
      static::adapter('default')->send();
                                                  Aware
    }

}

EmailAnother::config(array(
  'default' => array(
    'test' => array (
      'adapter' => 'EmailTest'
    ),
    'development' => array(
      'adapter' => 'EmailReal'
    ),
  )
));

EmailAnother::send();
Environment::set('development');

class EmailAnother extends Adaptable{             Already
    protected static $_configurations = array();
    protected static $_adapters = 'emails';
                                                  Environment
    public static function send() {
      static::adapter('default')->send();
                                                  Aware
    }

}

EmailAnother::config(array(
  'default' => array(
    'test' => array (
      'adapter' => 'EmailTest'
    ),
    'development' => array(
      'adapter' => 'EmailReal'
    ),
  )
));

EmailAnother::send();
Filters
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');

require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php';
require LITHIUM_LIBRARY_PATH . '/lithium/util/Collection.php';
require LITHIUM_LIBRARY_PATH . '/lithium/util/collection/Filters.php';

class Action extends lithiumcoreObject {

    public function doSomethingStupid() {
      return $this->_filter(__METHOD__, $params, function($self, $params) {
          $result = ‘Your girlfriend is angry at you’;
          return $result;
      });
    }
}

$action = new Action;
$action->applyFilter('doSomethingStupid', function($self, $params, $chain) {
  echo 'About to do something stupid,';
  $result = $chain->next($self, $params, $chain);
  echo 'You IDIOT!!!!!';
  return $result;
});

$action->doSomthingStupid();
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');

require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php';
require LITHIUM_LIBRARY_PATH . '/lithium/util/Collection.php';
require LITHIUM_LIBRARY_PATH . '/lithium/util/collection/Filters.php';

class Action extends lithiumcoreObject {

    public function doSomethingStupid() {
      return $this->_filter(__METHOD__, $params, function($self, $params) {
          $result = ‘Your girlfriend is angry at you’;
          return $result;

    }
      });
                                                                                 Make
}
                                                                               Filterable
$action = new Action;
$action->applyFilter('doSomethingStupid', function($self, $params, $chain) {
  echo 'About to do something stupid,';
  $result = $chain->next($self, $params, $chain);
  echo 'You IDIOT!!!!!';
  return $result;
});

$action->doSomthingStupid();
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');

require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php';
require LITHIUM_LIBRARY_PATH . '/lithium/util/Collection.php';
require LITHIUM_LIBRARY_PATH . '/lithium/util/collection/Filters.php';

class Action extends lithiumcoreObject {

    public function doSomethingStupid() {
      return $this->_filter(__METHOD__, $params, function($self, $params) {
          $result = ‘Your girlfriend is angry at you’;
          return $result;
      });
    }
}

$action = new Action;
$action->applyFilter('doSomethingStupid', function($self, $params, $chain) {
  echo 'About to do something stupid,';
  $result = $chain->next($self, $params, $chain);
  echo 'You IDIOT!!!!!';
  return $result;
});

$action->doSomthingStupid();
use lithiumanalysisLogger;

Logger::config(array(
  'default' => array(
    'adapter' => 'File',
    'path' => __DIR__ . '/crap/logs/'
  )
));


$action = new Action;
$action->applyFilter('doSomethingStupid', function($self, $params, $chain) {

 Logger::debug(date("D M j G:i:s") . " " . 'About to do something stupid,');

 $result = $chain->next($self, $params, $chain);

 Logger::debug(date("D M j G:i:s") . " " . 'You total moron!');

 return $result;

});

$action->doSomthingStupid();
use lithiumanalysisLogger;

Logger::config(array(
  'default' => array(
    'adapter' => 'File',
    'path' => __DIR__ . '/crap/logs/'
  )
));


$action = new Action;
$action->applyFilter('doSomethingStupid', function($self, $params, $chain) {

 Logger::debug(date("D M j G:i:s") . " " . 'About to do something stupid,');

 $result = $chain->next($self, $params, $chain);

 Logger::debug(date("D M j G:i:s") . " " . 'You total moron!');

 return $result;

});

$action->doSomthingStupid();
use lithiumanalysisLogger;

Logger::config(array(
  'default' => array(
    'adapter' => 'File',
    'path' => __DIR__ . '/crap/logs/'
  )
));


$action = new Action;
$action->applyFilter('doSomethingStupid', function($self, $params, $chain) {

 Logger::debug(date("D M j G:i:s") . " " . 'About to do something stupid,');

 $result = $chain->next($self, $params, $chain);

 Logger::debug(date("D M j G:i:s") . " " . 'You total moron!');

 return $result;

});

$action->doSomthingStupid();
use lithiumanalysisLogger;

Logger::config(array(
  'default' => array(
    'adapter' => 'File',
    'path' => __DIR__ . '/crap/logs/'
  )
));


$action = new Action;
$action->applyFilter('doSomethingStupid', function($self, $params, $chain) {

 Logger::debug(date("D M j G:i:s") . " " . 'About to do something stupid,');

 $result = $chain->next($self, $params, $chain);

 Logger::debug(date("D M j G:i:s") . " " . 'You total moron!');

 return $result;

});

$action->doSomthingStupid();
Lithium Best
Find
Cache

 Find
Log

Cache

 Find
Log

Cache

 Find
Log

Cache

 Find
Log

Cache

 Find
Posts::applyFilter('find', function($self, $params, $chain) {

 $result = $chain->next($self, $params, $chain);
 $search = http_build_query($params['options']);
 Logger::debug(
   'Search for: ' . $search . 'returned' . $result->to('json')
 );
 return $result;

});

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;

});
Posts::applyFilter('find', function($self, $params, $chain) {

 $result = $chain->next($self, $params, $chain);
 $search = http_build_query($params['options']);
 Logger::debug(
   'Search for: ' . $search . 'returned' . $result->to('json')
 );
 return $result;

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

});
Posts::applyFilter('find', function($self, $params, $chain) {

 $result = $chain->next($self, $params, $chain);
 $search = http_build_query($params['options']);
 Logger::debug(

 );                                                     Caching Filter
   'Search for: ' . $search . 'returned' . $result->to('json')

 return $result;

});

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;

});
Full Page Caching
Cache::config(array(
  'default' => array(
    'adapter' =>
      'lithiumstoragecacheadapter' . ($apcEnabled ? 'Apc' : 'File')
  )
));

Dispatcher::applyFilter('run', function($self, $params, $chain) {
 $key = md5(LITHIUM_APP_PATH) . '.app.cache.'.md5($params['request']->url);
 if($cache = Cache::read('default', $key)) {
   return $cache;
 }

 $result = $chain->next($self, $params, $chain);

  Cache::write('default', $key, $result, '+1 day');
  return $result;
});
Full Page Caching
                                                 Set Cache Configuration
Cache::config(array(
  'default' => array(
    'adapter' =>
      'lithiumstoragecacheadapter' . ($apcEnabled ? 'Apc' : 'File')
  )
));

Dispatcher::applyFilter('run', function($self, $params, $chain) {
 $key = md5(LITHIUM_APP_PATH) . '.app.cache.'.md5($params['request']->url);
 if($cache = Cache::read('default', $key)) {
   return $cache;
 }

 $result = $chain->next($self, $params, $chain);

  Cache::write('default', $key, $result, '+1 day');
  return $result;
});
Full Page Caching
Cache::config(array(
  'default' => array(
    'adapter' =>
      'lithiumstoragecacheadapter' . ($apcEnabled ? 'Apc' : 'File')
  )
));

Dispatcher::applyFilter('run', function($self, $params, $chain) {
 $key = md5(LITHIUM_APP_PATH) . '.app.cache.'.md5($params['request']->url);
 if($cache = Cache::read('default', $key)) {
   return $cache;
 }

 $result = $chain->next($self, $params, $chain);
                                                      Filter on Dispatcher::run
  Cache::write('default', $key, $result, '+1 day');   Checks for cache w/key
  return $result;
});
Full Page Caching
Cache::config(array(
  'default' => array(
    'adapter' =>
      'lithiumstoragecacheadapter' . ($apcEnabled ? 'Apc' : 'File')
  )
));


      w/out cache content carry on
Dispatcher::applyFilter('run', function($self, $params, $chain) {
 $key = md5(LITHIUM_APP_PATH) . '.app.cache.'.md5($params['request']->url);

        running - saving to cache
 if($cache = Cache::read('default', $key)) {
   return $cache;
 }

 $result = $chain->next($self, $params, $chain);

  Cache::write('default', $key, $result, '+1 day');
  return $result;
});
Content Rendering
namespace dispatcher_appcontrollers;

class YeaController extends lithiumactionController{
 public function index() {
   $yeah = true;
   return compact('yeah');
 }

    public function render(array $options = array()) {
      return 'The response of Yeah is: ' . $this->_render['data']['yeah'];
    }
}
Content Rendering
namespace dispatcher_appcontrollers;

class YeaController extends lithiumactionController{
 public function index() {
   $yeah = true;
   return compact('yeah');
 }

    public function render(array $options = array()) {
      return 'The response of Yeah is: ' . $this->_render['data']['yeah'];
    }
}
Content Rendering
namespace dispatcher_appcontrollers;

class YeaController extends lithiumactionController{
 public function index() {
   $yeah = true;
                      Overwrite ‘render’ method
   return compact('yeah');
 }

    public function render(array $options = array()) {
      return 'The response of Yeah is: ' . $this->_render['data']['yeah'];
    }
}
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');

require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;

Libraries::add('lithium');
Libraries::add('dispatcher_app', array('path' => __DIR__ . '/dispatcher_app'));

use lithiumnethttpRouter;
$router = new Router();

Router::connect('/cool-root', array('controller' => 'Yea', 'library' => 'dispatcher_app'));

echo lithiumactionDispatcher::run(
  new lithiumactionRequest()
);
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');

require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;

Libraries::add('lithium');
                                 Create Routing
Libraries::add('dispatcher_app', array('path' => __DIR__ . '/dispatcher_app'));

use lithiumnethttpRouter;
$router = new Router();

Router::connect('/cool-root', array('controller' => 'Yea', 'library' => 'dispatcher_app'));

echo lithiumactionDispatcher::run(
  new lithiumactionRequest()
);
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');

require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithiumcoreLibraries;

Libraries::add('lithium');
Libraries::add('dispatcher_app', array('path' => __DIR__ . '/dispatcher_app'));

use lithiumnethttpRouter;
$router = new Router();

                                                 Run Dispatcher
Router::connect('/cool-root', array('controller' => 'Yea', 'library' => 'dispatcher_app'));

echo lithiumactionDispatcher::run(
  new lithiumactionRequest()
);
Media Class
Media::type('ajax', array('application/xhtml+xml', 'text/html'), array(
  'view' => 'lithiumtemplateView',
  'paths' => array(
    'template' => array(
      '{:library}/views/{:controller}/{:template}.ajax.php',
      '{:library}/views/{:controller}/{:template}.html.php'
    ),
    'layout' => '{:library}/views/layouts/default.ajax.php'
  ),
  'conditions' => array('ajax' => true)
));




                                        Easily setup
                                      template paths
Media::type('jpg', 'image/jpeg', array('cast' => false, 'encode' => function($data) {
  return $data['photo']->file->getBytes();
}));

Media::type('json', 'application/json', array('cast' => false, 'encode' => function($data) {
  return json_encode($data);
}));

Media::type('json', 'application/json', array(
   'cast' => false, 'encode' => 'json_encode')
);
Media::type('jpg', 'image/jpeg', array('cast' => false, 'encode' => function($data) {
  return $data['photo']->file->getBytes();
}));

                                                            Handle Images
Media::type('json', 'application/json', array('cast' => false, 'encode' => function($data) {
  return json_encode($data);
}));

Media::type('json', 'application/json', array(
   'cast' => false, 'encode' => 'json_encode')
);
Media::type('jpg', 'image/jpeg', array('cast' => false, 'encode' => function($data) {
  return $data['photo']->file->getBytes();
}));

Media::type('json', 'application/json', array('cast' => false, 'encode' => function($data) {
  return json_encode($data);
}));

Media::type('json', 'application/json', array(
   'cast' => false, 'encode' => 'json_encode')
);
                                                        Handle JSON
Error Handling
Error Handling
use lithiumcoreErrorHandler;
use lithiumcoreStaticObject;

class IThrowAnException
{
  public function method() {
    throw new Exception('Yo');
  }
}

class IDontThrow extends StaticObject
{
  public static function method($bar) {
    static::_filter(__FUNCTION__, $params, function($self, $params) {
      $object = new IThrowAnException;
      $object->method();
    });
  }
}

ErrorHandler::apply('IDontThrow::method', array(), function($info, $params) {
  echo 'Exception raised with message - ' . $info['exception']->getMessage();
});

IDontThrowAnException::method();
Error Handling
use lithiumcoreErrorHandler;
use lithiumcoreStaticObject;

class IThrowAnException
{
  public function method() {
    throw new Exception('Yo');
  }
}

class IDontThrow extends StaticObject
{
  public static function method($bar) {
    static::_filter(__FUNCTION__, $params, function($self, $params) {
      $object = new IThrowAnException;
      $object->method();
    });
  }
}

ErrorHandler::apply('IDontThrow::method', array(), function($info, $params) {
  echo 'Exception raised with message - ' . $info['exception']->getMessage();
});

IDontThrowAnException::method();
Error Handling
use lithiumcoreErrorHandler;
use lithiumcoreStaticObject;

class IThrowAnException
{
  public function method() {
    throw new Exception('Yo');
  }                                                                             Filterable
}

class IDontThrow extends StaticObject
{
  public static function method($bar) {
    static::_filter(__FUNCTION__, $params, function($self, $params) {
      $object = new IThrowAnException;
      $object->method();
    });
  }
}

ErrorHandler::apply('IDontThrow::method', array(), function($info, $params) {
  echo 'Exception raised with message - ' . $info['exception']->getMessage();
});

IDontThrowAnException::method();
Error Handling
use lithiumcoreErrorHandler;
use lithiumcoreStaticObject;

class IThrowAnException
{
  public function method() {
    throw new Exception('Yo');
  }
}

class IDontThrow extends StaticObject
{
  public static function method($bar) {
    static::_filter(__FUNCTION__, $params, function($self, $params) {
      $object = new IThrowAnException;
      $object->method();
    });
  }
}

ErrorHandler::apply('IDontThrow::method', array(), function($info, $params) {
  echo 'Exception raised with message - ' . $info['exception']->getMessage();
});

IDontThrowAnException::method();
ErrorHandler::apply('lithiumactionDispatcher::run', array(),
 function($info, $params) {
 $response = new Response(array(
   'request' => $params['request'],
   'status' => $info['exception']->getCode(),
   'trace' => $info['exception']->getTrace(),
 ));

 Media::render($response, compact('info', 'params'), array(
  'controller' => 'errors',
  'template' => 'default',
  'layout' => 'default',
  'library' => 'golf',
  'request' => $params['request'],

  ));
  return $response;
});




                                                        Example
Create
ErrorHandler::apply('lithiumactionDispatcher::run', array(),
 function($info, $params) {
                                                                  Response
 $response = new Response(array(
   'request' => $params['request'],
   'status' => $info['exception']->getCode(),
   'trace' => $info['exception']->getTrace(),
 ));

 Media::render($response, compact('info', 'params'), array(
  'controller' => 'errors',
  'template' => 'default',
  'layout' => 'default',
  'library' => 'golf',
  'request' => $params['request'],

  ));
  return $response;
});




                                                        Example
ErrorHandler::apply('lithiumactionDispatcher::run', array(),
 function($info, $params) {
 $response = new Response(array(
   'request' => $params['request'],
   'status' => $info['exception']->getCode(),
   'trace' => $info['exception']->getTrace(),
 ));

 Media::render($response, compact('info', 'params'), array(
  'controller' => 'errors',
  'template' => 'default',
  'layout' => 'default',
  'library' => 'golf',                                            Media
  'request' => $params['request'],
                                                                  Render
  ));
  return $response;
});




                                                        Example
Zendy Love

Libraryies::add(
  'prefix' => 'Zend_',
  'includePath' => '/htdocs/libraries/Zend/trunk/library',
  'bootstrap' => 'Loader/Autoloader.php',
  'loader' => array('Zend_Loader_Autoloader', 'autoload'),
  'transform' => function($class) { return str_replace('_', '/', $class) . '.php'; }
);
define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries');
define('LITHIUM_APP_PATH', __DIR__ . '/templates');

require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use   lithiumcoreLibraries;
use   lithiumcoreEnvironment;
use   lithiumactionDispatcher;
use   lithiumg11nMessage;
use   lithiumnethttpMedia;

Libraries::add('lithium');
Libraries::add('li3_docs');
Libraries::add('templates', array('path' => __DIR__ . '/templates',
                               'default' => true));
Libraries::add('adapters', array('path' => __DIR__ . '/adapters'));

Libraries::add('li3_docs', array(
    'index' => array('lithium', 'adapters')
));




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

require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use   lithiumcoreLibraries;                                          Sets up
use   lithiumcoreEnvironment;
use
use
      lithiumactionDispatcher;
      lithiumg11nMessage;
                                                                      Libraries
use   lithiumnethttpMedia;

Libraries::add('lithium');
Libraries::add('li3_docs');
Libraries::add('templates', array('path' => __DIR__ . '/templates',
                               'default' => true));
Libraries::add('adapters', array('path' => __DIR__ . '/adapters'));

Libraries::add('li3_docs', array(
    'index' => array('lithium', 'adapters')
));




                            Libraries Example
$locale = 'en';
$locales = array('en' => 'English');

Environment::set('development', compact('locale', 'locales'));
Environment::set('development'); }
    $file = "{$config['path']}/config/routes.php";
    file_exists($file) ? call_user_func(function() use ($file) { include $file; }) : null;
  }
  return $chain->next($self, $params, $chain);
});

Media::applyFilter('_handle', function($self, $params, $chain) {
  $params['handler'] += array('outputFilters' => array());
  $params['handler']['outputFilters'] += Message::aliases();
  return $chain->next($self, $params, $chain);
});

echo lithiumactionDispatcher::run(new lithiumactionRequest());
Locale &
$locale = 'en';
                                                                                          Routes
$locales = array('en' => 'English');

Environment::set('development', compact('locale', 'locales'));
Environment::set('development'); }
    $file = "{$config['path']}/config/routes.php";
    file_exists($file) ? call_user_func(function() use ($file) { include $file; }) : null;
  }
  return $chain->next($self, $params, $chain);
});

Media::applyFilter('_handle', function($self, $params, $chain) {
  $params['handler'] += array('outputFilters' => array());
  $params['handler']['outputFilters'] += Message::aliases();
  return $chain->next($self, $params, $chain);
});

echo lithiumactionDispatcher::run(new lithiumactionRequest());
$locale = 'en';
$locales = array('en' => 'English');

Environment::set('development', compact('locale', 'locales'));
Environment::set('development'); }
    $file = "{$config['path']}/config/routes.php";
    file_exists($file) ? call_user_func(function() use ($file) { include $file; }) : null;
  }
  return $chain->next($self, $params, $chain);
});

Media::applyFilter('_handle', function($self, $params, $chain) {
  $params['handler'] += array('outputFilters' => array());
  $params['handler']['outputFilters'] += Message::aliases();
  return $chain->next($self, $params, $chain);
                                                                                             Gets
});                                                                                      translations
echo lithiumactionDispatcher::run(new lithiumactionRequest());
$locale = 'en';
$locales = array('en' => 'English');

Environment::set('development', compact('locale', 'locales'));
Environment::set('development'); }
    $file = "{$config['path']}/config/routes.php";
    file_exists($file) ? call_user_func(function() use ($file) { include $file; }) : null;
  }
  return $chain->next($self, $params, $chain);
});

Media::applyFilter('_handle', function($self, $params, $chain) {
  $params['handler'] += array('outputFilters' => array());
  $params['handler']['outputFilters'] += Message::aliases();
  return $chain->next($self, $params, $chain);
});

echo lithiumactionDispatcher::run(new lithiumactionRequest());




                               Go
Recap
★ Hackers framework
                      Recap
★ Hackers framework
                      Recap
★ Light, fast & fun
★ Hackers framework
                            Recap
★ Light, fast & fun

★ Services have adaptable base
★ Hackers framework
                            Recap
★ Light, fast & fun

★ Services have adaptable base

★ Filters are awesome/powerful
★ Hackers framework
                            Recap
★ Light, fast & fun

★ Services have adaptable base

★ Filters are awesome/powerful

★ Everything is a library
★ Hackers framework
                            Recap
★ Light, fast & fun

★ Services have adaptable base

★ Filters are awesome/powerful

★ Everything is a library

★ As much or as little framework as you
  need
★ Hackers framework
                            Recap
★ Light, fast & fun

★ Services have adaptable base

★ Filters are awesome/powerful

★ Everything is a library

★ As much or as little framework as you
  need

★ Great balance weight/power/simplicity
Thanks
github.com/mackstar/phpnw-li3




   @mackstar | #mackstar

More Related Content

What's hot

PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
G Woo
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
Fabien Potencier
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
Fabien Potencier
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
Fabien Potencier
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
jsmith92
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
Fabien Potencier
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
Hugo Hamon
 
Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8
PrinceGuru MS
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overview
jsmith92
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
Fabien Potencier
 
Future of HTTP in CakePHP
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHP
markstory
 
Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4
Fabien Potencier
 
Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3
José Lorenzo Rodríguez Urdaneta
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
Fabien Potencier
 
New in cakephp3
New in cakephp3New in cakephp3
New in cakephp3
markstory
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3
Fabien Potencier
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
Fabien Potencier
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
Hugo Hamon
 

What's hot (20)

PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overview
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Future of HTTP in CakePHP
Future of HTTP in CakePHPFuture of HTTP in CakePHP
Future of HTTP in CakePHP
 
Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4
 
Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3Advanced Querying with CakePHP 3
Advanced Querying with CakePHP 3
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 
New in cakephp3
New in cakephp3New in cakephp3
New in cakephp3
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 

Viewers also liked

چراغ پيشاني
چراغ پيشانيچراغ پيشاني
چراغ پيشاني
abas goodarzi
 
Potassium2
Potassium2Potassium2
Potassium2
mahmood mahmoodi
 
Pan American Lithium Corp. Investor Presentation
Pan American Lithium Corp. Investor PresentationPan American Lithium Corp. Investor Presentation
Pan American Lithium Corp. Investor Presentation
Company Spotlight
 
The lithium market: 2010 review and outlook
The lithium market: 2010 review and outlookThe lithium market: 2010 review and outlook
The lithium market: 2010 review and outlook
robertbaylis
 
GAC-MAC 2011 - Austman Et Al - Origin, Geology, and Composition of Fraser Lak...
GAC-MAC 2011 - Austman Et Al - Origin, Geology, and Composition of Fraser Lak...GAC-MAC 2011 - Austman Et Al - Origin, Geology, and Composition of Fraser Lak...
GAC-MAC 2011 - Austman Et Al - Origin, Geology, and Composition of Fraser Lak...
Christine McKechnie
 
Lithium Supply &amp; Markets 2010 Chairman\'s Opening Speech
Lithium Supply &amp; Markets 2010 Chairman\'s Opening SpeechLithium Supply &amp; Markets 2010 Chairman\'s Opening Speech
Lithium Supply &amp; Markets 2010 Chairman\'s Opening Speech
Simon Moores
 
Extraction and Applications of Rare Earth Metals and Alloys (Uranium, Lithium...
Extraction and Applications of Rare Earth Metals and Alloys (Uranium, Lithium...Extraction and Applications of Rare Earth Metals and Alloys (Uranium, Lithium...
Extraction and Applications of Rare Earth Metals and Alloys (Uranium, Lithium...
Ajjay Kumar Gupta
 
Cypress Development Corp. Corporate Presentation
Cypress Development Corp. Corporate PresentationCypress Development Corp. Corporate Presentation
Cypress Development Corp. Corporate Presentation
Company Spotlight
 
Advantage Lithium Corporate Presentation
Advantage Lithium Corporate PresentationAdvantage Lithium Corporate Presentation
Advantage Lithium Corporate Presentation
AdvantageLithium
 
Lithium
LithiumLithium
Lithium
Shah Parind
 
International Lithium: Presentation Of Our Strategic Partner - Ganfeng Lithiu...
International Lithium: Presentation Of Our Strategic Partner - Ganfeng Lithiu...International Lithium: Presentation Of Our Strategic Partner - Ganfeng Lithiu...
International Lithium: Presentation Of Our Strategic Partner - Ganfeng Lithiu...
Kirill Klip
 
International Lithium Introduction Presentation
International Lithium Introduction PresentationInternational Lithium Introduction Presentation
International Lithium Introduction Presentation
Kirill Klip
 
Parentswish
ParentswishParentswish
Parentswish
AAR VEE
 
The little ice age
The little ice ageThe little ice age
The little ice age
000175031
 
GözMobil
GözMobilGözMobil
GözMobil
ykeremyazici74
 
Visita monòverweb
Visita monòverwebVisita monòverweb
Visita monòverweb
iesMola
 
Angl
AnglAngl
[28 8] beantwoording 6 themavragen 1 september 2015
[28 8] beantwoording 6 themavragen 1 september 2015[28 8] beantwoording 6 themavragen 1 september 2015
[28 8] beantwoording 6 themavragen 1 september 2015
Reinoud Scheres
 

Viewers also liked (20)

چراغ پيشاني
چراغ پيشانيچراغ پيشاني
چراغ پيشاني
 
Potassium2
Potassium2Potassium2
Potassium2
 
Pan American Lithium Corp. Investor Presentation
Pan American Lithium Corp. Investor PresentationPan American Lithium Corp. Investor Presentation
Pan American Lithium Corp. Investor Presentation
 
The lithium market: 2010 review and outlook
The lithium market: 2010 review and outlookThe lithium market: 2010 review and outlook
The lithium market: 2010 review and outlook
 
GAC-MAC 2011 - Austman Et Al - Origin, Geology, and Composition of Fraser Lak...
GAC-MAC 2011 - Austman Et Al - Origin, Geology, and Composition of Fraser Lak...GAC-MAC 2011 - Austman Et Al - Origin, Geology, and Composition of Fraser Lak...
GAC-MAC 2011 - Austman Et Al - Origin, Geology, and Composition of Fraser Lak...
 
Lithium Supply &amp; Markets 2010 Chairman\'s Opening Speech
Lithium Supply &amp; Markets 2010 Chairman\'s Opening SpeechLithium Supply &amp; Markets 2010 Chairman\'s Opening Speech
Lithium Supply &amp; Markets 2010 Chairman\'s Opening Speech
 
Extraction and Applications of Rare Earth Metals and Alloys (Uranium, Lithium...
Extraction and Applications of Rare Earth Metals and Alloys (Uranium, Lithium...Extraction and Applications of Rare Earth Metals and Alloys (Uranium, Lithium...
Extraction and Applications of Rare Earth Metals and Alloys (Uranium, Lithium...
 
Cypress Development Corp. Corporate Presentation
Cypress Development Corp. Corporate PresentationCypress Development Corp. Corporate Presentation
Cypress Development Corp. Corporate Presentation
 
Advantage Lithium Corporate Presentation
Advantage Lithium Corporate PresentationAdvantage Lithium Corporate Presentation
Advantage Lithium Corporate Presentation
 
Lithium
LithiumLithium
Lithium
 
International Lithium: Presentation Of Our Strategic Partner - Ganfeng Lithiu...
International Lithium: Presentation Of Our Strategic Partner - Ganfeng Lithiu...International Lithium: Presentation Of Our Strategic Partner - Ganfeng Lithiu...
International Lithium: Presentation Of Our Strategic Partner - Ganfeng Lithiu...
 
International Lithium Introduction Presentation
International Lithium Introduction PresentationInternational Lithium Introduction Presentation
International Lithium Introduction Presentation
 
Parentswish
ParentswishParentswish
Parentswish
 
моап 2011 05
моап 2011 05моап 2011 05
моап 2011 05
 
The little ice age
The little ice ageThe little ice age
The little ice age
 
GözMobil
GözMobilGözMobil
GözMobil
 
Visita monòverweb
Visita monòverwebVisita monòverweb
Visita monòverweb
 
Angl
AnglAngl
Angl
 
[28 8] beantwoording 6 themavragen 1 september 2015
[28 8] beantwoording 6 themavragen 1 september 2015[28 8] beantwoording 6 themavragen 1 september 2015
[28 8] beantwoording 6 themavragen 1 september 2015
 
Eni gela
Eni   gelaEni   gela
Eni gela
 

Similar to Lithium Best

Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
Leonardo Proietti
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro Framework
Jeremy Kendall
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
Jeremy Kendall
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
Michelangelo van Dam
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
Michelangelo van Dam
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with Slim
Raven Tools
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
Michelangelo van Dam
 
Bacbkone js
Bacbkone jsBacbkone js
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
Lars Jankowfsky
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
Fabien Potencier
 
Apostrophe
ApostropheApostrophe
Apostrophe
tompunk
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
Stephan Hochdörfer
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
Massimiliano Arione
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
Nate Abele
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From Iusethis
Marcus Ramberg
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
Divante
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
Nishan Subedi
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
Konstantin Kudryashov
 
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
camp_drupal_ua
 

Similar to Lithium Best (20)

Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro Framework
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with Slim
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Bacbkone js
Bacbkone jsBacbkone js
Bacbkone js
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
Apostrophe
ApostropheApostrophe
Apostrophe
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
 
Migrare da symfony 1 a Symfony2
 Migrare da symfony 1 a Symfony2  Migrare da symfony 1 a Symfony2
Migrare da symfony 1 a Symfony2
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From Iusethis
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
Nickolay Shmalenuk.Render api eng.DrupalCamp Kyiv 2011
 

More from Richard McIntyre

Why Message Driven?
Why Message Driven?Why Message Driven?
Why Message Driven?
Richard McIntyre
 
Spout
SpoutSpout
Spout
SpoutSpout
Semantic BDD with ShouldIT?
Semantic BDD with ShouldIT?Semantic BDD with ShouldIT?
Semantic BDD with ShouldIT?
Richard McIntyre
 
Spout - Building a RESTful web app with Angular.js and BEAR.Sunday
Spout - Building a RESTful web app with Angular.js and BEAR.SundaySpout - Building a RESTful web app with Angular.js and BEAR.Sunday
Spout - Building a RESTful web app with Angular.js and BEAR.Sunday
Richard McIntyre
 
What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...
Richard McIntyre
 
Using Backbone with CakePHP
Using Backbone with CakePHPUsing Backbone with CakePHP
Using Backbone with CakePHP
Richard McIntyre
 
Future of PHP
Future of PHPFuture of PHP
Future of PHP
Richard McIntyre
 

More from Richard McIntyre (8)

Why Message Driven?
Why Message Driven?Why Message Driven?
Why Message Driven?
 
Spout
SpoutSpout
Spout
 
Spout
SpoutSpout
Spout
 
Semantic BDD with ShouldIT?
Semantic BDD with ShouldIT?Semantic BDD with ShouldIT?
Semantic BDD with ShouldIT?
 
Spout - Building a RESTful web app with Angular.js and BEAR.Sunday
Spout - Building a RESTful web app with Angular.js and BEAR.SundaySpout - Building a RESTful web app with Angular.js and BEAR.Sunday
Spout - Building a RESTful web app with Angular.js and BEAR.Sunday
 
What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...
 
Using Backbone with CakePHP
Using Backbone with CakePHPUsing Backbone with CakePHP
Using Backbone with CakePHP
 
Future of PHP
Future of PHPFuture of PHP
Future of PHP
 

Lithium Best

  • 1. Lithium (#li3) The framework with the best of both worlds
  • 2. Richard McIntyre: @mackstar ★ Lithium core team ★ Freelancer - Leeds/Manchester ★ Most recently at BBC, Mamas & Papas, UOR ★ Engineer on BBC Olympics App ★ Lived in Japan 15 years ★ Done PHP for donkeys
  • 6. I’ve seen it ✦ Symfony 2 ✦ Merb ✦ Zend Framework ✦ Sinatra ✦ CakePHP ✦ Spring ✦ Code Igniter ✦ Stripes (Java) ✦ Drupal 6&7 ✦ Django Wordpress ✦ Silex ✦ ✦ Rails
  • 9. Each software solution should be in proportion to the problem being solved.
  • 10. Each software solution should be in proportion to the problem being solved. -some lazy bugger
  • 11. Each software solution should be in proportion to the problem being solved. -some lazy bugger me
  • 12. <?php use BehatMinkExtensionContextMinkContext; class FeatureContext extends MinkContext { /** * @Then /^I wait for the suggestion box to appear$/ */ public function myNameHasAMeaninglessExistance() { $this->getSession()->wait(5000, "$('.suggestions-results').children().length > 0"); } }
  • 13. All problems in computer science can be solved by another level of indirection. Except for the problem of too many layers of indirection. Butler Lampson, David Wheeler
  • 14. Code Sexy-ness There’s nothing like the look of beautiful Ruby code in the morning. Gracefully colored by TextMate and rendered in Bitstream Vera pt 12. @dhh
  • 15. Developer Happy-ness Any fool can write code that a computer can understand. Good programmers write code that humans can understand. –Martin Fowler
  • 18. Looking for a hackers Framework? Light Footprint
  • 20. World 1 Full Stack Framework Convention Over Configuration
  • 22. The Photo Blog Tutorial github.com/nateabele/photoblog
  • 23. Model namespace photoblogmodels; class Photos extends lithiumdataModel { public $validates = array(); protected $_meta = array('source' => 'fs.files'); public function save($entity, $data = null, array $options = array()) { if ($data) { $entity->set($data); } if ($entity->tags && !is_array($entity->tags)) { $entity->tags = array_map('trim', explode(',', $entity->tags)); } return parent::save($entity, null, $options); } }
  • 24. Model namespace photoblogmodels; class Photos extends lithiumdataModel { public $validates = array(); protected $_meta = array('source' => 'fs.files'); public function save($entity, $data = null, array $options = array()) { if ($data) { $entity->set($data); } if ($entity->tags && !is_array($entity->tags)) { $entity->tags = array_map('trim', explode(',', $entity->tags)); } return parent::save($entity, null, $options); } }
  • 25. Model namespace photoblogmodels; class Photos extends lithiumdataModel { public $validates = array(); protected $_meta = array('source' => 'fs.files'); public function save($entity, $data = null, array $options = array()) { if ($data) { $entity->set($data); } if ($entity->tags && !is_array($entity->tags)) { $entity->tags = array_map('trim', explode(',', $entity->tags)); } return parent::save($entity, null, $options); } }
  • 26. Views <?=$this->form->create($photo, array('type' => 'file')); ?> <?=$this->form->field('title'); ?> <?=$this->form->field('description'); ?> <?php if (!$photo->exists()): ?> <?=$this->form->field('file', array('type' => 'file')); ?> <?php endif; ?> <?=$this->form->field('tags', array('label' => 'Add tags separated by commas')); ?> <?=$this->form->submit('Save'); ?> <?=$this->form->end(); ?>
  • 27. Views <?=$this->form->create($photo, array('type' => 'file')); ?> <?=$this->form->field('title'); ?> <?=$this->form->field('description'); ?> <?php if (!$photo->exists()): ?> <?=$this->form->field('file', array('type' => 'file')); ?> <?php endif; ?> <?=$this->form->field('tags', array('label' => 'Add tags separated by commas')); ?> <?=$this->form->submit('Save'); ?> <?=$this->form->end(); ?>
  • 28. Views <?=$this->form->create($photo, array('type' => 'file')); ?> <?=$this->form->field('title'); ?> <?=$this->form->field('description'); ?> <?php if (!$photo->exists()): ?> <?=$this->form->field('file', array('type' => 'file')); ?> <?php endif; ?> <?=$this->form->field('tags', array('label' => 'Add tags separated by commas')); ?> <?=$this->form->submit('Save'); ?> <?=$this->form->end(); ?>
  • 29. <h1> <?=$this->title($photo->title); ?> <em>[ <?=$this->html->link( 'edit', array('Photos::edit', 'id' => $photo->_id) ); ?> ]</em> </h1> <p><?=$photo->description; ?></p> <?php if ($photo->tags): ?> Tags: <?php foreach ($photo->tags as $tag): ?> <?=$this->html->link( $tag, array('Photos::index', 'args' => array($tag)) ); ?> <?php endforeach; ?> <?php endif; ?> <?=$this->html->image( "/photos/view/{$photo->_id}.jpeg", array( 'alt' => $photo->title, 'width' => "100%" ) ); ?>
  • 30. <h1> <?=$this->title($photo->title); ?> <em>[ <?=$this->html->link( 'edit', array('Photos::edit', 'id' => $photo->_id) ); ?> ]</em> </h1> <p><?=$photo->description; ?></p> <?php if ($photo->tags): ?> Tags: <?php foreach ($photo->tags as $tag): ?> <?=$this->html->link( $tag, array('Photos::index', 'args' => array($tag)) ); ?> <?php endforeach; ?> <?php endif; ?> <?=$this->html->image( "/photos/view/{$photo->_id}.jpeg", array( 'alt' => $photo->title, 'width' => "100%" ) ); ?>
  • 31. <h1> <?=$this->title($photo->title); ?> <em>[ <?=$this->html->link( 'edit', array('Photos::edit', 'id' => $photo->_id) ); ?> ]</em> </h1> <p><?=$photo->description; ?></p> <?php if ($photo->tags): ?> Tags: <?php foreach ($photo->tags as $tag): ?> <?=$this->html->link( $tag, array('Photos::index', 'args' => array($tag)) ); ?> <?php endforeach; ?> <?php endif; ?> <?=$this->html->image( "/photos/view/{$photo->_id}.jpeg", array( 'alt' => $photo->title, 'width' => "100%" ) ); ?>
  • 32. Controller namespace photoblogcontrollers; use photoblogmodelsPhotos; use li3_geoextensionsGeocoder; class PhotosController extends lithiumactionController { public function index($tags = null) { $conditions = $tags ? compact('tags') : array(); $photos = Photos::all(compact('conditions')); return compact('photos'); } public function view() { $photo = Photos::first($this->request->id); return compact('photo'); }
  • 33. Controller namespace photoblogcontrollers; use photoblogmodelsPhotos; use li3_geoextensionsGeocoder; class PhotosController extends lithiumactionController { public function index($tags = null) { $conditions = $tags ? compact('tags') : array(); $photos = Photos::all(compact('conditions')); return compact('photos'); } public function view() { $photo = Photos::first($this->request->id); return compact('photo'); }
  • 34. Controller namespace photoblogcontrollers; use photoblogmodelsPhotos; use li3_geoextensionsGeocoder; class PhotosController extends lithiumactionController { public function index($tags = null) { $conditions = $tags ? compact('tags') : array(); $photos = Photos::all(compact('conditions')); return compact('photos'); } public function view() { $photo = Photos::first($this->request->id); return compact('photo'); }
  • 35. public function near($place = null) { $this->_render['template'] = 'index'; $coords = Geocoder::find('google', $place); $photos = Photos::within(array($coords, $coords), array('limit' => 1)); return compact('photos'); } public function add() { $photo = Photos::create(); if (($this->request->data) && $photo->save($this->request->data)) { $this->redirect(array('Photos::view', 'id' => $photo->_id)); } $this->_render['template'] = 'edit'; return compact('photo'); } public function edit() { $photo = Photos::find($this->request->id); if (!$photo) { $this->redirect('Photos::index'); } if (($this->request->data) && $photo->save($this->request->data)) { $this->redirect(array('Photos::view', 'id' => $photo->_id)); } return compact('photo'); }
  • 36. public function near($place = null) { $this->_render['template'] = 'index'; $coords = Geocoder::find('google', $place); $photos = Photos::within(array($coords, $coords), array('limit' => 1)); return compact('photos'); } public function add() { $photo = Photos::create(); Geo Location if (($this->request->data) && $photo->save($this->request->data)) { $this->redirect(array('Photos::view', 'id' => $photo->_id)); } $this->_render['template'] = 'edit'; return compact('photo'); } public function edit() { $photo = Photos::find($this->request->id); if (!$photo) { $this->redirect('Photos::index'); } if (($this->request->data) && $photo->save($this->request->data)) { $this->redirect(array('Photos::view', 'id' => $photo->_id)); } return compact('photo'); }
  • 37. Routes use lithiumnethttpRouter; use lithiumcoreEnvironment; use lithiumactionResponse; use photoblogmodelsPhotos; Router::connect('/photos/view/{:id:[0-9a-f]{24}}.jpeg', array(), function($request) { return new Response(array( 'headers' => array('Content-type' => 'image/jpeg'), 'body' => Photos::first($request->id)->file->getBytes() )); }); /** * Connect the testing routes. */ if (!Environment::is('production')) { Router::connect('/test/{:args}', array('controller' => 'lithiumtestController')); Router::connect('/test', array('controller' => 'lithiumtestController')); }
  • 38. Routes use lithiumnethttpRouter; use lithiumcoreEnvironment; use lithiumactionResponse; use photoblogmodelsPhotos; Router::connect('/photos/view/{:id:[0-9a-f]{24}}.jpeg', array(), function($request) { return new Response(array( 'headers' => array('Content-type' => 'image/jpeg'), 'body' => Photos::first($request->id)->file->getBytes() )); }); /** * Connect the testing routes. By-Passes */ if (!Environment::is('production')) { the framework Router::connect('/test/{:args}', array('controller' => 'lithiumtestController')); Router::connect('/test', array('controller' => 'lithiumtestController')); }
  • 39. Routes use lithiumnethttpRouter; use lithiumcoreEnvironment; use lithiumactionResponse; use It’s PHP you can photoblogmodelsPhotos; Router::connect('/photos/view/{:id:[0-9a-f]{24}}.jpeg', array(), function($request) { return new Response(array( you doarray('Content-type' => 'image/jpeg'), what 'headers' => want 'body' => Photos::first($request->id)->file->getBytes() )); }); /** * Connect the testing routes. */ if (!Environment::is('production')) { Router::connect('/test/{:args}', array('controller' => 'lithiumtestController')); Router::connect('/test', array('controller' => 'lithiumtestController')); }
  • 41. Features ✦ Full stack MVC ✦ Object based record- sets ✦ Logger ✦ Command Line ✦ Caching Framework ✦ Sessions/Cookies ✦ Authentication ✦ Full templating suite ✦ Validator ✦ Integrated TDD suite ✦ Http Services
  • 43. Now for some fun!
  • 44. World 2 Kick-ass de-coupled hacker happy framework
  • 45. Are you a slave to your framework?
  • 49. Database namespace models; class Posts extends lithiumdataModel { }
  • 50. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); use lithiumdataConnections; Connections::add('default', array( 'type' => 'MongoDb', 'database' => 'phpnw', 'host' => 'localhost' )); Libraries::add('models', array('path' => __DIR__ . '/models')); use modelsPosts; $posts = Posts::create(array('title' => 'Hi Guys')); $posts->save();
  • 51. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); Simple lithium setup use lithiumdataConnections; Connections::add('default', array( 'type' => 'MongoDb', 'database' => 'phpnw', 'host' => 'localhost' )); Libraries::add('models', array('path' => __DIR__ . '/models')); use modelsPosts; $posts = Posts::create(array('title' => 'Hi Guys')); $posts->save();
  • 52. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); use lithiumdataConnections; Connections::add('default', array( 'type' => 'MongoDb', 'database' => 'phpnw', DB Config 'host' => 'localhost' )); Libraries::add('models', array('path' => __DIR__ . '/models')); use modelsPosts; $posts = Posts::create(array('title' => 'Hi Guys')); $posts->save();
  • 53. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); use lithiumdataConnections; Connections::add('default', array( 'type' => 'MongoDb', 'database' => 'phpnw', 'host' => 'localhost' )); Add models ‘app’ Libraries::add('models', array('path' => __DIR__ . '/models')); use modelsPosts; $posts = Posts::create(array('title' => 'Hi Guys')); $posts->save();
  • 54. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); use lithiumdataConnections; Connections::add('default', array( 'type' => 'MongoDb', 'database' => 'phpnw', 'host' => 'localhost' )); DB Save Libraries::add('models', array('path' => __DIR__ . '/models')); use modelsPosts; $posts = Posts::create(array('title' => 'Hi Guys')); $posts->save();
  • 55. Routes define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); use lithiumnethttpRouter; use lithiumactionRequest; $request = new Request(); $router = new Router(); $router->connect('/cool-root', array('controller' => 'Yea')); $router->connect('/cool-root/{:application_id:[0-9]{1}}', array('controller' => 'Yea')); $router->parse($request); echo Router::match('Yea::index'); echo Router::match(array('Yea::index', 'application_id' => 1));
  • 56. Routes define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); use lithiumnethttpRouter; use lithiumactionRequest; $request = new Request(); $router = new Router(); $router->connect('/cool-root', array('controller' => 'Yea')); $router->connect('/cool-root/{:application_id:[0-9]{1}}', array('controller' => 'Yea')); $router->parse($request); echo Router::match('Yea::index'); echo Router::match(array('Yea::index', 'application_id' => 1));
  • 57. Routes define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); use lithiumnethttpRouter; use lithiumactionRequest; $request = new Request(); $router = new Router(); $router->connect('/cool-root', array('controller' => 'Yea')); $router->connect('/cool-root/{:application_id:[0-9]{1}}', array('controller' => 'Yea')); $router->parse($request); echo Router::match('Yea::index'); echo Router::match(array('Yea::index', 'application_id' => 1));
  • 58. Routes define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); use lithiumnethttpRouter; use lithiumactionRequest; $request = new Request(); $router = new Router(); $router->connect('/cool-root', array('controller' => 'Yea')); $router->connect('/cool-root/{:application_id:[0-9]{1}}', array('controller' => 'Yea')); $router->parse($request); echo Router::match('Yea::index'); echo Router::match(array('Yea::index', 'application_id' => 1));
  • 62. /cool-root/4 $router->connect('/cool-root/{:application_id:[0-9]{1}}', array('controller' => 'Yea')); object(lithiumactionRequest)[1] public 'url' => string '/cool-root/4' (length=12) public 'params' => array (size=3) 'application_id' => string '4' (length=1) 'controller' => string 'Yea' (length=3) 'action' => string 'index' (length=5)
  • 63. Adaptable Classes define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); define('LITHIUM_APP_PATH', __DIR__); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php'; require LITHIUM_LIBRARY_PATH . '/lithium/core/StaticObject.php'; require LITHIUM_LIBRARY_PATH . '/lithium/core/Environment.php'; require LITHIUM_LIBRARY_PATH . '/lithium/core/Adaptable.php'; use lithiumcoreAdaptable; class Email extends Adaptable{ protected static $_configurations = array(); protected static $_adapters = 'emails'; }
  • 64. Adaptable Classes define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); define('LITHIUM_APP_PATH', __DIR__); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php'; require LITHIUM_LIBRARY_PATH . '/lithium/core/StaticObject.php'; require LITHIUM_LIBRARY_PATH . '/lithium/core/Environment.php'; require LITHIUM_LIBRARY_PATH . '/lithium/core/Adaptable.php'; use lithiumcoreAdaptable; class Email extends Adaptable{ protected static $_configurations = array(); protected static $_adapters = 'emails'; }
  • 65. namespace adapters; use lithiumcoreLibraries; Libraries::add('lithium'); class EmailTest Libraries::add('adapters', { array('path' => __DIR__ . '/adapters')); public function send() { Libraries::paths( echo 'email test send'; array('emails' => array( } '{:library}{:name}'))); } Email::config(array( 'development' => array( 'adapter' => 'EmailReal' ), namespace adapters; 'test' => array( 'adapter' => 'EmailTest' class EmailReal ), { )); public function send() { echo 'email real send'; use lithiumcoreEnvironment; } } Environment::set('test'); $env = Environment::get(); Email::adapter($env)->send();
  • 66. namespace adapters; use lithiumcoreLibraries; Libraries::add('lithium'); class EmailTest Libraries::add('adapters', { array('path' => __DIR__ . '/adapters')); public function send() { Libraries::paths( echo 'email test send'; array('emails' => array( } '{:library}{:name}'))); } Email::config(array( 'development' => array( 'adapter' => 'EmailReal' ), namespace adapters; 'test' => array( 'adapter' => 'EmailTest' class EmailReal ), { )); public function send() { echo 'email real send'; use lithiumcoreEnvironment; } } Environment::set('test'); $env = Environment::get(); Email::adapter($env)->send();
  • 67. namespace adapters; use lithiumcoreLibraries; Libraries::add('lithium'); class EmailTest Libraries::add('adapters', { array('path' => __DIR__ . '/adapters')); public function send() { Libraries::paths( echo 'email test send'; array('emails' => array( } '{:library}{:name}'))); } Email::config(array( 'development' => array( 'adapter' => 'EmailReal' ), namespace adapters; 'test' => array( 'adapter' => 'EmailTest' class EmailReal ), { )); public function send() { echo 'email real send'; use lithiumcoreEnvironment; } } Environment::set('test'); $env = Environment::get(); Email::adapter($env)->send();
  • 68. namespace adapters; use lithiumcoreLibraries; Libraries::add('lithium'); class EmailTest Libraries::add('adapters', { array('path' => __DIR__ . '/adapters')); public function send() { Libraries::paths( echo 'email test send'; array('emails' => array( } '{:library}{:name}'))); } Email::config(array( 'development' => array( 'adapter' => 'EmailReal' ), namespace adapters; 'test' => array( 'adapter' => 'EmailTest' class EmailReal ), { )); public function send() { echo 'email real send'; use lithiumcoreEnvironment; } } Environment::set('test'); $env = Environment::get(); Email::adapter($env)->send();
  • 69. Environment::set('development'); class EmailAnother extends Adaptable{ Already protected static $_configurations = array(); protected static $_adapters = 'emails'; Environment public static function send() { static::adapter('default')->send(); Aware } } EmailAnother::config(array( 'default' => array( 'test' => array ( 'adapter' => 'EmailTest' ), 'development' => array( 'adapter' => 'EmailReal' ), ) )); EmailAnother::send();
  • 70. Environment::set('development'); class EmailAnother extends Adaptable{ Already protected static $_configurations = array(); protected static $_adapters = 'emails'; Environment public static function send() { static::adapter('default')->send(); Aware } } EmailAnother::config(array( 'default' => array( 'test' => array ( 'adapter' => 'EmailTest' ), 'development' => array( 'adapter' => 'EmailReal' ), ) )); EmailAnother::send();
  • 71. Environment::set('development'); class EmailAnother extends Adaptable{ Already protected static $_configurations = array(); protected static $_adapters = 'emails'; Environment public static function send() { static::adapter('default')->send(); Aware } } EmailAnother::config(array( 'default' => array( 'test' => array ( 'adapter' => 'EmailTest' ), 'development' => array( 'adapter' => 'EmailReal' ), ) )); EmailAnother::send();
  • 72. Environment::set('development'); class EmailAnother extends Adaptable{ Already protected static $_configurations = array(); protected static $_adapters = 'emails'; Environment public static function send() { static::adapter('default')->send(); Aware } } EmailAnother::config(array( 'default' => array( 'test' => array ( 'adapter' => 'EmailTest' ), 'development' => array( 'adapter' => 'EmailReal' ), ) )); EmailAnother::send();
  • 74. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php'; require LITHIUM_LIBRARY_PATH . '/lithium/util/Collection.php'; require LITHIUM_LIBRARY_PATH . '/lithium/util/collection/Filters.php'; class Action extends lithiumcoreObject { public function doSomethingStupid() { return $this->_filter(__METHOD__, $params, function($self, $params) { $result = ‘Your girlfriend is angry at you’; return $result; }); } } $action = new Action; $action->applyFilter('doSomethingStupid', function($self, $params, $chain) { echo 'About to do something stupid,'; $result = $chain->next($self, $params, $chain); echo 'You IDIOT!!!!!'; return $result; }); $action->doSomthingStupid();
  • 75. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php'; require LITHIUM_LIBRARY_PATH . '/lithium/util/Collection.php'; require LITHIUM_LIBRARY_PATH . '/lithium/util/collection/Filters.php'; class Action extends lithiumcoreObject { public function doSomethingStupid() { return $this->_filter(__METHOD__, $params, function($self, $params) { $result = ‘Your girlfriend is angry at you’; return $result; } }); Make } Filterable $action = new Action; $action->applyFilter('doSomethingStupid', function($self, $params, $chain) { echo 'About to do something stupid,'; $result = $chain->next($self, $params, $chain); echo 'You IDIOT!!!!!'; return $result; }); $action->doSomthingStupid();
  • 76. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php'; require LITHIUM_LIBRARY_PATH . '/lithium/util/Collection.php'; require LITHIUM_LIBRARY_PATH . '/lithium/util/collection/Filters.php'; class Action extends lithiumcoreObject { public function doSomethingStupid() { return $this->_filter(__METHOD__, $params, function($self, $params) { $result = ‘Your girlfriend is angry at you’; return $result; }); } } $action = new Action; $action->applyFilter('doSomethingStupid', function($self, $params, $chain) { echo 'About to do something stupid,'; $result = $chain->next($self, $params, $chain); echo 'You IDIOT!!!!!'; return $result; }); $action->doSomthingStupid();
  • 77. use lithiumanalysisLogger; Logger::config(array( 'default' => array( 'adapter' => 'File', 'path' => __DIR__ . '/crap/logs/' ) )); $action = new Action; $action->applyFilter('doSomethingStupid', function($self, $params, $chain) { Logger::debug(date("D M j G:i:s") . " " . 'About to do something stupid,'); $result = $chain->next($self, $params, $chain); Logger::debug(date("D M j G:i:s") . " " . 'You total moron!'); return $result; }); $action->doSomthingStupid();
  • 78. use lithiumanalysisLogger; Logger::config(array( 'default' => array( 'adapter' => 'File', 'path' => __DIR__ . '/crap/logs/' ) )); $action = new Action; $action->applyFilter('doSomethingStupid', function($self, $params, $chain) { Logger::debug(date("D M j G:i:s") . " " . 'About to do something stupid,'); $result = $chain->next($self, $params, $chain); Logger::debug(date("D M j G:i:s") . " " . 'You total moron!'); return $result; }); $action->doSomthingStupid();
  • 79. use lithiumanalysisLogger; Logger::config(array( 'default' => array( 'adapter' => 'File', 'path' => __DIR__ . '/crap/logs/' ) )); $action = new Action; $action->applyFilter('doSomethingStupid', function($self, $params, $chain) { Logger::debug(date("D M j G:i:s") . " " . 'About to do something stupid,'); $result = $chain->next($self, $params, $chain); Logger::debug(date("D M j G:i:s") . " " . 'You total moron!'); return $result; }); $action->doSomthingStupid();
  • 80. use lithiumanalysisLogger; Logger::config(array( 'default' => array( 'adapter' => 'File', 'path' => __DIR__ . '/crap/logs/' ) )); $action = new Action; $action->applyFilter('doSomethingStupid', function($self, $params, $chain) { Logger::debug(date("D M j G:i:s") . " " . 'About to do something stupid,'); $result = $chain->next($self, $params, $chain); Logger::debug(date("D M j G:i:s") . " " . 'You total moron!'); return $result; }); $action->doSomthingStupid();
  • 82. Find
  • 88. Posts::applyFilter('find', function($self, $params, $chain) { $result = $chain->next($self, $params, $chain); $search = http_build_query($params['options']); Logger::debug( 'Search for: ' . $search . 'returned' . $result->to('json') ); return $result; }); 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; });
  • 89. Posts::applyFilter('find', function($self, $params, $chain) { $result = $chain->next($self, $params, $chain); $search = http_build_query($params['options']); Logger::debug( 'Search for: ' . $search . 'returned' . $result->to('json') ); return $result; }); Logging Filter 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; });
  • 90. Posts::applyFilter('find', function($self, $params, $chain) { $result = $chain->next($self, $params, $chain); $search = http_build_query($params['options']); Logger::debug( ); Caching Filter 'Search for: ' . $search . 'returned' . $result->to('json') return $result; }); 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; });
  • 91. Full Page Caching Cache::config(array( 'default' => array( 'adapter' => 'lithiumstoragecacheadapter' . ($apcEnabled ? 'Apc' : 'File') ) )); Dispatcher::applyFilter('run', function($self, $params, $chain) { $key = md5(LITHIUM_APP_PATH) . '.app.cache.'.md5($params['request']->url); if($cache = Cache::read('default', $key)) { return $cache; } $result = $chain->next($self, $params, $chain); Cache::write('default', $key, $result, '+1 day'); return $result; });
  • 92. Full Page Caching Set Cache Configuration Cache::config(array( 'default' => array( 'adapter' => 'lithiumstoragecacheadapter' . ($apcEnabled ? 'Apc' : 'File') ) )); Dispatcher::applyFilter('run', function($self, $params, $chain) { $key = md5(LITHIUM_APP_PATH) . '.app.cache.'.md5($params['request']->url); if($cache = Cache::read('default', $key)) { return $cache; } $result = $chain->next($self, $params, $chain); Cache::write('default', $key, $result, '+1 day'); return $result; });
  • 93. Full Page Caching Cache::config(array( 'default' => array( 'adapter' => 'lithiumstoragecacheadapter' . ($apcEnabled ? 'Apc' : 'File') ) )); Dispatcher::applyFilter('run', function($self, $params, $chain) { $key = md5(LITHIUM_APP_PATH) . '.app.cache.'.md5($params['request']->url); if($cache = Cache::read('default', $key)) { return $cache; } $result = $chain->next($self, $params, $chain); Filter on Dispatcher::run Cache::write('default', $key, $result, '+1 day'); Checks for cache w/key return $result; });
  • 94. Full Page Caching Cache::config(array( 'default' => array( 'adapter' => 'lithiumstoragecacheadapter' . ($apcEnabled ? 'Apc' : 'File') ) )); w/out cache content carry on Dispatcher::applyFilter('run', function($self, $params, $chain) { $key = md5(LITHIUM_APP_PATH) . '.app.cache.'.md5($params['request']->url); running - saving to cache if($cache = Cache::read('default', $key)) { return $cache; } $result = $chain->next($self, $params, $chain); Cache::write('default', $key, $result, '+1 day'); return $result; });
  • 95. Content Rendering namespace dispatcher_appcontrollers; class YeaController extends lithiumactionController{ public function index() { $yeah = true; return compact('yeah'); } public function render(array $options = array()) { return 'The response of Yeah is: ' . $this->_render['data']['yeah']; } }
  • 96. Content Rendering namespace dispatcher_appcontrollers; class YeaController extends lithiumactionController{ public function index() { $yeah = true; return compact('yeah'); } public function render(array $options = array()) { return 'The response of Yeah is: ' . $this->_render['data']['yeah']; } }
  • 97. Content Rendering namespace dispatcher_appcontrollers; class YeaController extends lithiumactionController{ public function index() { $yeah = true; Overwrite ‘render’ method return compact('yeah'); } public function render(array $options = array()) { return 'The response of Yeah is: ' . $this->_render['data']['yeah']; } }
  • 98. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); Libraries::add('dispatcher_app', array('path' => __DIR__ . '/dispatcher_app')); use lithiumnethttpRouter; $router = new Router(); Router::connect('/cool-root', array('controller' => 'Yea', 'library' => 'dispatcher_app')); echo lithiumactionDispatcher::run( new lithiumactionRequest() );
  • 99. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); Create Routing Libraries::add('dispatcher_app', array('path' => __DIR__ . '/dispatcher_app')); use lithiumnethttpRouter; $router = new Router(); Router::connect('/cool-root', array('controller' => 'Yea', 'library' => 'dispatcher_app')); echo lithiumactionDispatcher::run( new lithiumactionRequest() );
  • 100. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Libraries::add('lithium'); Libraries::add('dispatcher_app', array('path' => __DIR__ . '/dispatcher_app')); use lithiumnethttpRouter; $router = new Router(); Run Dispatcher Router::connect('/cool-root', array('controller' => 'Yea', 'library' => 'dispatcher_app')); echo lithiumactionDispatcher::run( new lithiumactionRequest() );
  • 102. Media::type('ajax', array('application/xhtml+xml', 'text/html'), array( 'view' => 'lithiumtemplateView', 'paths' => array( 'template' => array( '{:library}/views/{:controller}/{:template}.ajax.php', '{:library}/views/{:controller}/{:template}.html.php' ), 'layout' => '{:library}/views/layouts/default.ajax.php' ), 'conditions' => array('ajax' => true) )); Easily setup template paths
  • 103. Media::type('jpg', 'image/jpeg', array('cast' => false, 'encode' => function($data) { return $data['photo']->file->getBytes(); })); Media::type('json', 'application/json', array('cast' => false, 'encode' => function($data) { return json_encode($data); })); Media::type('json', 'application/json', array( 'cast' => false, 'encode' => 'json_encode') );
  • 104. Media::type('jpg', 'image/jpeg', array('cast' => false, 'encode' => function($data) { return $data['photo']->file->getBytes(); })); Handle Images Media::type('json', 'application/json', array('cast' => false, 'encode' => function($data) { return json_encode($data); })); Media::type('json', 'application/json', array( 'cast' => false, 'encode' => 'json_encode') );
  • 105. Media::type('jpg', 'image/jpeg', array('cast' => false, 'encode' => function($data) { return $data['photo']->file->getBytes(); })); Media::type('json', 'application/json', array('cast' => false, 'encode' => function($data) { return json_encode($data); })); Media::type('json', 'application/json', array( 'cast' => false, 'encode' => 'json_encode') ); Handle JSON
  • 107. Error Handling use lithiumcoreErrorHandler; use lithiumcoreStaticObject; class IThrowAnException { public function method() { throw new Exception('Yo'); } } class IDontThrow extends StaticObject { public static function method($bar) { static::_filter(__FUNCTION__, $params, function($self, $params) { $object = new IThrowAnException; $object->method(); }); } } ErrorHandler::apply('IDontThrow::method', array(), function($info, $params) { echo 'Exception raised with message - ' . $info['exception']->getMessage(); }); IDontThrowAnException::method();
  • 108. Error Handling use lithiumcoreErrorHandler; use lithiumcoreStaticObject; class IThrowAnException { public function method() { throw new Exception('Yo'); } } class IDontThrow extends StaticObject { public static function method($bar) { static::_filter(__FUNCTION__, $params, function($self, $params) { $object = new IThrowAnException; $object->method(); }); } } ErrorHandler::apply('IDontThrow::method', array(), function($info, $params) { echo 'Exception raised with message - ' . $info['exception']->getMessage(); }); IDontThrowAnException::method();
  • 109. Error Handling use lithiumcoreErrorHandler; use lithiumcoreStaticObject; class IThrowAnException { public function method() { throw new Exception('Yo'); } Filterable } class IDontThrow extends StaticObject { public static function method($bar) { static::_filter(__FUNCTION__, $params, function($self, $params) { $object = new IThrowAnException; $object->method(); }); } } ErrorHandler::apply('IDontThrow::method', array(), function($info, $params) { echo 'Exception raised with message - ' . $info['exception']->getMessage(); }); IDontThrowAnException::method();
  • 110. Error Handling use lithiumcoreErrorHandler; use lithiumcoreStaticObject; class IThrowAnException { public function method() { throw new Exception('Yo'); } } class IDontThrow extends StaticObject { public static function method($bar) { static::_filter(__FUNCTION__, $params, function($self, $params) { $object = new IThrowAnException; $object->method(); }); } } ErrorHandler::apply('IDontThrow::method', array(), function($info, $params) { echo 'Exception raised with message - ' . $info['exception']->getMessage(); }); IDontThrowAnException::method();
  • 111. ErrorHandler::apply('lithiumactionDispatcher::run', array(), function($info, $params) { $response = new Response(array( 'request' => $params['request'], 'status' => $info['exception']->getCode(), 'trace' => $info['exception']->getTrace(), )); Media::render($response, compact('info', 'params'), array( 'controller' => 'errors', 'template' => 'default', 'layout' => 'default', 'library' => 'golf', 'request' => $params['request'], )); return $response; }); Example
  • 112. Create ErrorHandler::apply('lithiumactionDispatcher::run', array(), function($info, $params) { Response $response = new Response(array( 'request' => $params['request'], 'status' => $info['exception']->getCode(), 'trace' => $info['exception']->getTrace(), )); Media::render($response, compact('info', 'params'), array( 'controller' => 'errors', 'template' => 'default', 'layout' => 'default', 'library' => 'golf', 'request' => $params['request'], )); return $response; }); Example
  • 113. ErrorHandler::apply('lithiumactionDispatcher::run', array(), function($info, $params) { $response = new Response(array( 'request' => $params['request'], 'status' => $info['exception']->getCode(), 'trace' => $info['exception']->getTrace(), )); Media::render($response, compact('info', 'params'), array( 'controller' => 'errors', 'template' => 'default', 'layout' => 'default', 'library' => 'golf', Media 'request' => $params['request'], Render )); return $response; }); Example
  • 114. Zendy Love Libraryies::add( 'prefix' => 'Zend_', 'includePath' => '/htdocs/libraries/Zend/trunk/library', 'bootstrap' => 'Loader/Autoloader.php', 'loader' => array('Zend_Loader_Autoloader', 'autoload'), 'transform' => function($class) { return str_replace('_', '/', $class) . '.php'; } );
  • 115. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); define('LITHIUM_APP_PATH', __DIR__ . '/templates'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; use lithiumcoreEnvironment; use lithiumactionDispatcher; use lithiumg11nMessage; use lithiumnethttpMedia; Libraries::add('lithium'); Libraries::add('li3_docs'); Libraries::add('templates', array('path' => __DIR__ . '/templates', 'default' => true)); Libraries::add('adapters', array('path' => __DIR__ . '/adapters')); Libraries::add('li3_docs', array( 'index' => array('lithium', 'adapters') )); Libraries Example
  • 116. define('LITHIUM_LIBRARY_PATH', dirname(__DIR__) . '/libraries'); define('LITHIUM_APP_PATH', __DIR__ . '/templates'); require LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php'; use lithiumcoreLibraries; Sets up use lithiumcoreEnvironment; use use lithiumactionDispatcher; lithiumg11nMessage; Libraries use lithiumnethttpMedia; Libraries::add('lithium'); Libraries::add('li3_docs'); Libraries::add('templates', array('path' => __DIR__ . '/templates', 'default' => true)); Libraries::add('adapters', array('path' => __DIR__ . '/adapters')); Libraries::add('li3_docs', array( 'index' => array('lithium', 'adapters') )); Libraries Example
  • 117. $locale = 'en'; $locales = array('en' => 'English'); Environment::set('development', compact('locale', 'locales')); Environment::set('development'); } $file = "{$config['path']}/config/routes.php"; file_exists($file) ? call_user_func(function() use ($file) { include $file; }) : null; } return $chain->next($self, $params, $chain); }); Media::applyFilter('_handle', function($self, $params, $chain) { $params['handler'] += array('outputFilters' => array()); $params['handler']['outputFilters'] += Message::aliases(); return $chain->next($self, $params, $chain); }); echo lithiumactionDispatcher::run(new lithiumactionRequest());
  • 118. Locale & $locale = 'en'; Routes $locales = array('en' => 'English'); Environment::set('development', compact('locale', 'locales')); Environment::set('development'); } $file = "{$config['path']}/config/routes.php"; file_exists($file) ? call_user_func(function() use ($file) { include $file; }) : null; } return $chain->next($self, $params, $chain); }); Media::applyFilter('_handle', function($self, $params, $chain) { $params['handler'] += array('outputFilters' => array()); $params['handler']['outputFilters'] += Message::aliases(); return $chain->next($self, $params, $chain); }); echo lithiumactionDispatcher::run(new lithiumactionRequest());
  • 119. $locale = 'en'; $locales = array('en' => 'English'); Environment::set('development', compact('locale', 'locales')); Environment::set('development'); } $file = "{$config['path']}/config/routes.php"; file_exists($file) ? call_user_func(function() use ($file) { include $file; }) : null; } return $chain->next($self, $params, $chain); }); Media::applyFilter('_handle', function($self, $params, $chain) { $params['handler'] += array('outputFilters' => array()); $params['handler']['outputFilters'] += Message::aliases(); return $chain->next($self, $params, $chain); Gets }); translations echo lithiumactionDispatcher::run(new lithiumactionRequest());
  • 120. $locale = 'en'; $locales = array('en' => 'English'); Environment::set('development', compact('locale', 'locales')); Environment::set('development'); } $file = "{$config['path']}/config/routes.php"; file_exists($file) ? call_user_func(function() use ($file) { include $file; }) : null; } return $chain->next($self, $params, $chain); }); Media::applyFilter('_handle', function($self, $params, $chain) { $params['handler'] += array('outputFilters' => array()); $params['handler']['outputFilters'] += Message::aliases(); return $chain->next($self, $params, $chain); }); echo lithiumactionDispatcher::run(new lithiumactionRequest()); Go
  • 121. Recap
  • 123. ★ Hackers framework Recap ★ Light, fast & fun
  • 124. ★ Hackers framework Recap ★ Light, fast & fun ★ Services have adaptable base
  • 125. ★ Hackers framework Recap ★ Light, fast & fun ★ Services have adaptable base ★ Filters are awesome/powerful
  • 126. ★ Hackers framework Recap ★ Light, fast & fun ★ Services have adaptable base ★ Filters are awesome/powerful ★ Everything is a library
  • 127. ★ Hackers framework Recap ★ Light, fast & fun ★ Services have adaptable base ★ Filters are awesome/powerful ★ Everything is a library ★ As much or as little framework as you need
  • 128. ★ Hackers framework Recap ★ Light, fast & fun ★ Services have adaptable base ★ Filters are awesome/powerful ★ Everything is a library ★ As much or as little framework as you need ★ Great balance weight/power/simplicity
  • 129. Thanks github.com/mackstar/phpnw-li3 @mackstar | #mackstar

Editor's Notes

  1. \n
  2. Union of Rad - worked with Nate\nTalk to me about japan\n
  3. Thank you - engine yard sponsors Lithium - php 5.4\n
  4. Lets talk about frameworks - there are too many\n
  5. People like to fight about their framework choice\n
  6. My favorites\nMy Least favorites\n
  7. Bloated\nCarry too much bulk - Symfony/Doctrine - VHeavy\nJava programmers\n
  8. \n
  9. \n
  10. Any body else find this odd?\n
  11. \n
  12. What drives us -\nIt is important to love the code you write - rails has had a big influence\n
  13. Our feelings count\nI don&amp;#x2019;t think we should need a high powered ide\n
  14. Lithium is really light 1mb tests 1mb - no bulk\n
  15. Lithium is really light 1mb tests 1mb - no bulk\n
  16. It is fast to develop in, it will speed up your development time. \nCompare Symfony, ZF, Drupal\n
  17. World one - every one familiar with this phrase?\n
  18. The repo - skeleton\n
  19. Great way to familiarize yourself - next few slides are taken from this project\n
  20. Example model - Save override to save tags\n
  21. Example model - Save override to save tags\n
  22. Example model - Save override to save tags\n
  23. View helpers\nCan override these\n
  24. View helpers\nCan override these\n
  25. View helpers\nCan override these\n
  26. &lt;?= escaping\nLink routes\nimage url helper\n
  27. &lt;?= escaping\nLink routes\nimage url helper\n
  28. &lt;?= escaping\nLink routes\nimage url helper\n
  29. Easy to read controllers - simple methods\n
  30. Easy to read controllers - simple methods\n
  31. Easy to read controllers - simple methods\n
  32. Geo-code is here - still really simple\n
  33. 1.Completely avoids the framework stack\nCan also use with JSON end points\n2. Its PHP, you can do what you want \n
  34. 1.Completely avoids the framework stack\nCan also use with JSON end points\n2. Its PHP, you can do what you want \n
  35. 1.Completely avoids the framework stack\nCan also use with JSON end points\n2. Its PHP, you can do what you want \n
  36. testing important\neverything is a library\n
  37. command line\n
  38. But this alone is not massively different to what is out there - like fuel\n
  39. It gets more interesting from here\n
  40. world 2\n
  41. Sky - no framework - create it from scratch - framework constraints\n
  42. maybe we feel a bit like this\n
  43. Not just 1 programming paradigm - php is very flexible\n
  44. \n
  45. Make a simple model\n
  46. Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
  47. Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
  48. Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
  49. Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
  50. Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
  51. Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
  52. Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
  53. Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
  54. Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
  55. Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
  56. Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
  57. Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
  58. We have an end point, \nfollowing route, \nparses the request object to contain\n
  59. We have an end point, \nfollowing route, \nparses the request object to contain\n
  60. We have an end point, \nfollowing route, \nparses the request object to contain\n
  61. Make simplest adaptable class\n
  62. We tell the Lithium where the app and adapters live -normally not needed\n-note emails same as where highlighted in the class \nSet the environment and use the adapter\n
  63. We tell the Lithium where the app and adapters live -normally not needed\n-note emails same as where highlighted in the class \nSet the environment and use the adapter\n
  64. We tell the Lithium where the app and adapters live -normally not needed\n-note emails same as where highlighted in the class \nSet the environment and use the adapter\n
  65. We tell the Lithium where the app and adapters live -normally not needed\n-note emails same as where highlighted in the class \nSet the environment and use the adapter\n
  66. We tell the Lithium where the app and adapters live -normally not needed\n-note emails same as where highlighted in the class \nSet the environment and use the adapter\n
  67. This time we write it a little more differently\nset up environment aware config\nSending is easy. Base of lithium services. Strategy implementation, very testable. DI in proportion\n
  68. This time we write it a little more differently\nset up environment aware config\nSending is easy. Base of lithium services. Strategy implementation, very testable. DI in proportion\n
  69. This time we write it a little more differently\nset up environment aware config\nSending is easy. Base of lithium services. Strategy implementation, very testable. DI in proportion\n
  70. This time we write it a little more differently\nset up environment aware config\nSending is easy. Base of lithium services. Strategy implementation, very testable. DI in proportion\n
  71. This time we write it a little more differently\nset up environment aware config\nSending is easy. Base of lithium services. Strategy implementation, very testable. DI in proportion\n
  72. The real fun part, this is a real high point of lithiums architecture.\n
  73. Write a method that doesn&amp;#x2019;t really do anything, but this is a filterable class\nEcho-ing is non-sense\n
  74. Write a method that doesn&amp;#x2019;t really do anything, but this is a filterable class\nEcho-ing is non-sense\n
  75. Write a method that doesn&amp;#x2019;t really do anything, but this is a filterable class\nEcho-ing is non-sense\n
  76. We deal with dependencies that have nothing to do with role\nLogger\n
  77. We deal with dependencies that have nothing to do with role\nLogger\n
  78. We deal with dependencies that have nothing to do with role\nLogger\n
  79. We deal with dependencies that have nothing to do with role\nLogger\n
  80. We deal with dependencies that have nothing to do with role\nLogger\n
  81. Find Example\n
  82. Find Example\n
  83. Find Example\n
  84. Find Example\n
  85. Find Example\n
  86. Find Example\n
  87. It would look like this\n
  88. It would look like this\n
  89. It would look like this\n
  90. Cache is an adaptable class\nBAD - filter classes that relates to itself\n
  91. Cache is an adaptable class\nBAD - filter classes that relates to itself\n
  92. Cache is an adaptable class\nBAD - filter classes that relates to itself\n
  93. Cache is an adaptable class\nBAD - filter classes that relates to itself\n
  94. Cache is an adaptable class\nBAD - filter classes that relates to itself\n
  95. Override content render - I am doing this\n
  96. Override content render - I am doing this\n
  97. Override content render - I am doing this\n
  98. \n
  99. \n
  100. \n
  101. How controller render works\n
  102. Ajax paths - types \n
  103. Handle media returned from the controller - images, json, encoding handlers\nHappens in controllers render method\n
  104. Handle media returned from the controller - images, json, encoding handlers\nHappens in controllers render method\n
  105. Handle media returned from the controller - images, json, encoding handlers\nHappens in controllers render method\n
  106. Granular control of exception handling\n
  107. Granular control of exception handling\n
  108. Granular control of exception handling\n
  109. Granular control of exception handling\n
  110. Granular control of exception handling\n
  111. Granular control of exception handling\n
  112. Real example - setting up error handling\n
  113. Real example - setting up error handling\n
  114. Real example - setting up error handling\n
  115. \n
  116. \n
  117. Set up stuff required by library - do demo\n
  118. Set up stuff required by library - do demo\n
  119. Set up stuff required by library - do demo\n
  120. Set up stuff required by library - do demo\n
  121. Set up stuff required by library - do demo\n
  122. Recap -really fast development\n
  123. Recap -really fast development\n
  124. Recap -really fast development\n
  125. Recap -really fast development\n
  126. Recap -really fast development\n
  127. Recap -really fast development\n
  128. Recap -really fast development\n
  129. \n