Advertisement
Advertisement

More Related Content

Advertisement

Less Time, Less Code, Less Headache

  1. LESS TIME LESS CODE LESS HEADACHE Lithium: 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 photoblog Bonus 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.php require __DIR__ . '/bootstrap/connections.php'; photoblog/config/bootstrap/connections.php use lithiumdataConnections; Connections::add('default', array( 'type' => 'MongoDb', 'host' => 'localhost', 'database' => 'photoblog' ));
  8. ALTERNATIVES... photoblog/config/bootstrap/connections.php use lithiumdataConnections; Connections::add('default', array( 'type' => 'http', 'adapter' => 'CouchDb', 'host' => 'localhost', 'database' => 'app' ));
  9. ALTERNATIVES... photoblog/config/bootstrap/connections.php use lithiumdataConnections; Connections::add('default', array( 'type' => 'database', 'adapter' => 'MySql', 'host' => 'localhost', 'login' => 'web', 'password' => 'sekrit', 'database' => 'app' ));
  10. $ li3 create Photos Photos 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.php class 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.php class 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.php Router::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.php Router::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.php Media::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 handler View Layout json_encode( )
  29. photoblog/config/routes.php use 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.php Media::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.git Note – 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.php use 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.php use 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.php use lithiumanalysisLogger; use lithiumdataConnections; Logger::config(array( 'default' => array('adapter' => 'File') ));
  46. photoblog/config/bootstrap/logging.php Connections::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.php Connections::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.log 2011-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 Resources lithify.me bit.ly/aop-design github.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

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
Advertisement