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
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
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'));
}
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
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()
);
★ 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
Union of Rad - worked with Nate\nTalk to me about japan\n
Thank you - engine yard sponsors Lithium - php 5.4\n
Lets talk about frameworks - there are too many\n
People like to fight about their framework choice\n
My favorites\nMy Least favorites\n
Bloated\nCarry too much bulk - Symfony/Doctrine - VHeavy\nJava programmers\n
\n
\n
Any body else find this odd?\n
\n
What drives us -\nIt is important to love the code you write - rails has had a big influence\n
Our feelings count\nI don&#x2019;t think we should need a high powered ide\n
Lithium is really light 1mb tests 1mb - no bulk\n
Lithium is really light 1mb tests 1mb - no bulk\n
It is fast to develop in, it will speed up your development time. \nCompare Symfony, ZF, Drupal\n
World one - every one familiar with this phrase?\n
The repo - skeleton\n
Great way to familiarize yourself - next few slides are taken from this project\n
Example model - Save override to save tags\n
Example model - Save override to save tags\n
Example model - Save override to save tags\n
View helpers\nCan override these\n
View helpers\nCan override these\n
View helpers\nCan override these\n
<?= escaping\nLink routes\nimage url helper\n
<?= escaping\nLink routes\nimage url helper\n
<?= escaping\nLink routes\nimage url helper\n
Easy to read controllers - simple methods\n
Easy to read controllers - simple methods\n
Easy to read controllers - simple methods\n
Geo-code is here - still really simple\n
1.Completely avoids the framework stack\nCan also use with JSON end points\n2. Its PHP, you can do what you want \n
1.Completely avoids the framework stack\nCan also use with JSON end points\n2. Its PHP, you can do what you want \n
1.Completely avoids the framework stack\nCan also use with JSON end points\n2. Its PHP, you can do what you want \n
testing important\neverything is a library\n
command line\n
But this alone is not massively different to what is out there - like fuel\n
It gets more interesting from here\n
world 2\n
Sky - no framework - create it from scratch - framework constraints\n
maybe we feel a bit like this\n
Not just 1 programming paradigm - php is very flexible\n
\n
Make a simple model\n
Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
Decoupled example\njust add lithium library - low overhead - all the code you need\nEasily added to DB - These are working examples\n
Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
Instantiate request and router\nSet routes - regex - now works (request contains correct controller)\nFull path matching\n\n\n
We have an end point, \nfollowing route, \nparses the request object to contain\n
We have an end point, \nfollowing route, \nparses the request object to contain\n
We have an end point, \nfollowing route, \nparses the request object to contain\n
Make simplest adaptable class\n
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
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
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
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
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
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
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
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
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
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
The real fun part, this is a real high point of lithiums architecture.\n
Write a method that doesn&#x2019;t really do anything, but this is a filterable class\nEcho-ing is non-sense\n
Write a method that doesn&#x2019;t really do anything, but this is a filterable class\nEcho-ing is non-sense\n
Write a method that doesn&#x2019;t really do anything, but this is a filterable class\nEcho-ing is non-sense\n
We deal with dependencies that have nothing to do with role\nLogger\n
We deal with dependencies that have nothing to do with role\nLogger\n
We deal with dependencies that have nothing to do with role\nLogger\n
We deal with dependencies that have nothing to do with role\nLogger\n
We deal with dependencies that have nothing to do with role\nLogger\n
Find Example\n
Find Example\n
Find Example\n
Find Example\n
Find Example\n
Find Example\n
It would look like this\n
It would look like this\n
It would look like this\n
Cache is an adaptable class\nBAD - filter classes that relates to itself\n
Cache is an adaptable class\nBAD - filter classes that relates to itself\n
Cache is an adaptable class\nBAD - filter classes that relates to itself\n
Cache is an adaptable class\nBAD - filter classes that relates to itself\n
Cache is an adaptable class\nBAD - filter classes that relates to itself\n
Override content render - I am doing this\n
Override content render - I am doing this\n
Override content render - I am doing this\n
\n
\n
\n
How controller render works\n
Ajax paths - types \n
Handle media returned from the controller - images, json, encoding handlers\nHappens in controllers render method\n
Handle media returned from the controller - images, json, encoding handlers\nHappens in controllers render method\n
Handle media returned from the controller - images, json, encoding handlers\nHappens in controllers render method\n