Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Less Time, Less Code, Less Headache

14,630 views

Published on

Learn how developing with the Lithium framework for PHP 5.3+ not only allows you to develop applications on tighter deadlines, but how Lithium's unique, superior architecture allows much-improved maintainability over the life of your apps.

Published in: Technology
  • Be the first to comment

Less Time, Less Code, Less Headache

  1. LESS TIME LESS CODE LESS HEADACHELithium: the framework that tries to suck less
  2. THE GOAL• Posting with photo upload• RSS updates• Geo-tagged images & geo-spatial search• Logging?
  3. $ git clone git://dev.lithify.me/lithium.git photoblogBonus Points – add the li3 command to your system PATH:http://bit.ly/li3path
  4. http://path/to/web/photoblog
  5. $ cd photoblog/app$ chmod -R 777 resources/
  6. http://path/to/web/photoblog
  7. photoblog/config/bootstrap.phprequire __DIR__ . /bootstrap/connections.php;photoblog/config/bootstrap/connections.phpuse lithiumdataConnections;Connections::add(default, array( type => MongoDb, host => localhost, database => photoblog));
  8. ALTERNATIVES...photoblog/config/bootstrap/connections.phpuse lithiumdataConnections;Connections::add(default, array( type => http, adapter => CouchDb, host => localhost, database => app));
  9. ALTERNATIVES...photoblog/config/bootstrap/connections.phpuse lithiumdataConnections;Connections::add(default, array( type => database, adapter => MySql, host => localhost, login => web, password => sekrit, database => app));
  10. $ li3 create PhotosPhotos created in appmodels.PhotosController created in appcontrollers.PhotosTest created in apptestscasesmodels.PhotosControllerTest created in apptestscasescontrollers.
  11. http://path/to/web/photoblog/photos
  12. photoblog/controllers/PhotosController.phpclass PhotosController extends lithiumactionController { public function index() { $photos = Photos::all(); return compact(photos); } // ...}
  13. photoblog/views/photos/index.html.php<?php if (!count($photos)): ?> <em>No photos</em>. <?=$this->html->link(Add one, Photos::add); ?>.<?php endif ?>
  14. http://path/to/web/photoblog/photos
  15. photoblog/controllers/PhotosController.php public function add() { $photo = Photo::create(); if (($this->request->data) && $photo->save($this->request->data)) { $this->redirect(array(Photos::view, id => $photo->_id)); $this->redirect(array(Photos::view, id => $photo->_id)); } $this->_render[template] = edit; return compact(photo); }
  16. photoblog/views/photos/edit.html.php<?=$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 } ?> <?=$this->form->submit(Save); ?><?=$this->form->end(); ?>
  17. http://path/to/web/photoblog/photos/add
  18. photoblog/models/Photos.phpclass Photo extends lithiumdataModel { public $validates = array(); protected $_meta = array(source => fs.files);}
  19. http://path/to/web/photoblog/photos/add
  20. http://path/to/web/photoblog/photos/add
  21. photoblog/config/routes.phpRouter::connect(/{:controller}/{:action}/{:id:[0-9a-f]{24}}.{:type}, array(id => null));Router::connect(/{:controller}/{:action}/{:id:[0-9a-f]{24}});
  22. photoblog/config/routes.phpRouter::connect(/{:controller}/{:action}/{:id:[0-9a-f]{24}}.{:type}, array(id => null));Router::connect(/{:controller}/{:action}/{:id:[0-9a-f]{24}}); {:id:[0-9a-f]{24}}
  23. http://path/to/web/photoblog/photos/view/...
  24. photoblog/views/photos/view.html.php<h1><?=$photo->title; ?></h1><p><?=$photo->description; ?></p><p> <?=$this->html->link(Edit, array(Photos::edit, id => $photo->_id)); ?></p><?=$this->html->image("/photos/view/{$photo->_id}.jpg", array( alt => $photo->title, width => 500)); ?>
  25. http://path/to/web/photoblog/photos/view/...
  26. photoblog/config/bootstrap.php/** * This file contains configurations for handling different * content types within the framework, including converting data to * and from different formats, and handling static media assets. */require __DIR__ . /bootstrap/media.php;photoblog/config/bootstrap/media.phpMedia::type(jpg, image/jpeg, array( cast => false, encode => function($data) { return $data[photo]->file->getBytes(); }));
  27. http://path/to/web/photoblog/photos/view/...
  28. Router::connect(/.../{:id:[0-9a-f]{24}}. {:type} {:type}, array(...)); Controller $photo Media HTML JSON JPEG templateView => array( ) Media type handlerView Layout json_encode( )
  29. photoblog/config/routes.phpuse appmodelsPhotos;use lithiumactionResponse;Router::connect(/photos/view/{:id:[0-9a-f]{24}}.jpg, array(), function($request) { return new Response(array( headers => array(Content-type => image/jpeg), body => Photos::first($request->id)->file->getBytes() ));});
  30. photoblog/views/photos/index.html.php<ul><?php foreach ($photos as $photo): ?> <li> <?=$this->html->link($photo->title, array( controller => photos, action => view, id => $photo->_id )); ?> </li><?php endforeach ?></ul>
  31. http://path/to/web/photoblog/photos
  32. photoblog/views/photos/index.html.php<ul><?php foreach ($photos as $photo): ?> <li> <?=$this->html->image( "/photos/view/{$photo->_id}.jpg", array(width=> 100) ); ?> <?=$this->html->link( $photo->title, array(Photos::view, id => $photo->_id) array(Photos::view, id => $photo->_id) ); ?> </li><?php endforeach ?></ul>
  33. http://path/to/web/photoblog/photos
  34. photoblog/config/bootstrap/media.phpMedia::type(rss, application/rss+xml);
  35. photoblog/views/layouts/default.rss.php<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"> <channel> <title>Photos</title> <pubDate> <?=date("D, j M Y H:i:s", gmmktime()) . GMT; ?> </pubDate> <?=$this->content(); ?> </channel></rss>
  36. photoblog/views/photos/index.rss.php<?php foreach ($photos as $photo): ?><item> <title><?=$photo->title; ?></title> <link><?=$this->url(array(Photos::view, id => $photo->_id)); ?></link> <description><?=$photo->description; ?></description></item><?php endforeach; ?>
  37. http://path/to/web/photoblog/photos.rss
  38. http://path/to/web/photoblog/photos.json[{ "photo": { "_id": "4d70c5017675ab4de900001f", "title": "FML", "description": "How the subway schedule sometimes makes me feel.", "filename": "FML.jpg", "uploadDate": 1299236097, "length": 452751, "chunkSize": 262144, "md5": "e74c961185efdd69acbccaa59b7b13c0", "file": { ... } }}]
  39. $ cd libraries/$ git clone code@dev.lithify.me:li3_geo.gitNote – you will need an account. Sign up here:http://dev.lithify.me/users/add
  40. photoblog/config/bootstrap/libraries.php/** * Add some plugins */Libraries::add(li3_geo);
  41. photoblog/models/Photos.phpuse li3_geoextensionsGeocoder;use li3_geoextensionsdatabehaviorLocatable;class Photos extends lithiumdataModel { // ... public static function __init() { parent::__init(); Locatable::bind(__CLASS__, array(fields => array( location.latitude, location.longitude ))); }}
  42. photoblog/models/Photos.php public function save($entity, $data = null, array $options = array()) { if ($data) { $entity->set($data); } if (!$entity->exists() && isset($entity->file->tmp_name)) { $entity->location = Geocoder::exifCoords( exif_read_data($entity->file->tmp_name) ); } return parent::save($entity, null, $options); }
  43. photoblog/controllers/PhotosController.phpuse li3_geoextensionsGeocoder;// ... public function near($place = null) { $this->_render[template] = index; $location = Geocoder::find(google, $place); $photos = Photos::near($location, array(limit => 5)); return compact(photos); }
  44. http://.../photos/near/New+York,+NY
  45. photoblog/config/bootstrap/logging.phpuse lithiumanalysisLogger;use lithiumdataConnections;Logger::config(array( default => array(adapter => File)));
  46. photoblog/config/bootstrap/logging.phpConnections::get(default)->applyFilter(read, function($self, $params, $chain) { $query = $params[query]; Logger::debug( Read: . $query->source() . : . json_encode($query->conditions()) ); return $chain->next($self, $params, $chain);});
  47. photoblog/config/bootstrap/logging.phpConnections::get(default)->applyFilter(update, function($self, $params, $chain) { $query = $params[query]; $data = json_encode($query->conditions()) . , . json_encode($query->data()); Logger::debug(Update: . $query->source() . ": {$data}"); return $chain->next($self, $params, $chain);});
  48. photoblog/resources/tmp/logs/debug.log2011-03-04 18:37:07 Read: fs.files: {"location":{"$near":{"latitude":40.7143528,"longitude":-74.0059731}}}2011-03-04 18:37:07 Read: fs.files: {"_id":"4d710afc7675ab95d0000004"}
  49. Thanks, y’all!Getting connected AOP Resourceslithify.me bit.ly/aop-designgithub.com/UnionOfRAD bit.ly/aop-gwoo#li3 on irc.freenode.net bit.ly/aop-li3@nateabele bit.ly/aop-oop@UnionOfRAD bit.ly/mwop-aop

×