Keeping it small: Getting to know the Slim micro framework

87,465 views
95,928 views

Published on

Published in: Technology
1 Comment
74 Likes
Statistics
Notes
  • This is real take it serious, who will believe that a herb can cure herpes, i navel believe that this will work i have spend a lot when getting drugs from the hospital to keep me healthy, what i was waiting for is death because i was broke, one day i hard about this great man who is well know of HIV and cancer cure, i decided to email him, unknowingly to me that this will be the end of the herpes in my body, he prepare the herb for me, and give me instruction on how to take it, at the end of the one month, he told me to go to the hospital for a check up, and i went, surprisingly after the test the doctor confirm me negative, i thought it was a joke, i went to other hospital was also negative, then i took my friend who was also herpes positive to the Dr Agumagu, after the treatment she was also confirm negative . He also have the herb to cure cancer. please i want every one with this virus to be free, that is why am dropping his email address, agumaguspelltemple@outlook.com or agumaguspelltemple@gmail.com do email him he is a great man. the government is also interested in this DR, thank you for saving my life, and I promise I will always testify for your good work call his number +233200116937
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
87,465
On SlideShare
0
From Embeds
0
Number of Embeds
48,806
Actions
Shares
0
Downloads
1,129
Comments
1
Likes
74
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • WTF?\n
  • Blame it on github and their repo name suggetsions\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Four views\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Can be anything that returns true for is_callable()\n\n
  • Can be anything that returns true for is_callable()\n\n
  • Can be anything that returns true for is_callable()\n\n
  • Can be anything that returns true for is_callable()\n\n
  • Can be anything that returns true for is_callable()\n\n
  • Can be anything that returns true for is_callable()\n\n
  • Can be anything that returns true for is_callable()\n\n
  • Can be anything that returns true for is_callable()\n\n
  • GET, including route parameters and conditions\n
  • GET, including route parameters and conditions\n
  • GET, including route parameters and conditions\n
  • GET, including route parameters and conditions\n
  • GET, including route parameters and conditions\n
  • GET, including route parameters and conditions\n
  • GET, including route parameters and conditions\n
  • GET, including route parameters and conditions\n
  • GET, including route parameters and conditions\n
  • GET, including route parameters and conditions\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  • slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  • slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  • slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  • slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  • slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  • slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  • Has access to app, environment, request & response object\n
  • Has access to app, environment, request & response object\n
  • Has access to app, environment, request & response object\n
  • Has access to app, environment, request & response object\n
  • Has access to app, environment, request & response object\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • I won’t cover bootstrap, but it kicks ass\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Too much boilerplate to show off, but here come the important parts\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Keeping it small: Getting to know the Slim micro framework

    1. 1. Keeping it smallGetting to know the Slim micro framework @JeremyKendall
    2. 2. Jeremy Kendallraventools.com
    3. 3. Jeremy Kendall I love to coderaventools.com
    4. 4. Jeremy Kendall I love to code I’m terribly forgetfulraventools.com
    5. 5. Jeremy Kendall I love to code I’m terribly forgetful I take picturesraventools.com
    6. 6. Jeremy Kendall I love to code I’m terribly forgetful I take picturesraventools.com I work at Raven
    7. 7. Micro framework?
    8. 8. Micro framework?Concise codebase
    9. 9. Micro framework?Concise codebaseClear codebase
    10. 10. Micro framework?Concise codebaseClear codebaseAddresses a small set of use cases
    11. 11. Micro framework?Concise codebaseClear codebaseAddresses a small set of use casesAddresses those use cases well
    12. 12. What is Slim?
    13. 13. What is Slim?Inspired by Sinatra
    14. 14. What is Slim?Inspired by SinatraFavors cleanliness over terseness
    15. 15. What is Slim?Inspired by SinatraFavors cleanliness over tersenessFavors common cases over edge cases
    16. 16. Installing Slim
    17. 17. RTFM
    18. 18. RTFM ;-)
    19. 19. Don’t forget .htaccess!RewriteEngine OnRewriteCond %{REQUEST_FILENAME} !-fRewriteRule ^ index.php [QSA,L]http://docs.slimframework.com/pages/routing-url-rewriting/
    20. 20. Hello world<?phprequire ../vendor/autoload.php;$app = new SlimSlim();$app->get(/hello/:name, function ($name) { echo "Hello, $name";});$app->run();
    21. 21. Hello world<?phprequire ../vendor/autoload.php;$app = new SlimSlim();$app->get(/hello/:name, function ($name) { echo "Hello, $name";});$app->run();
    22. 22. Hello world<?phprequire ../vendor/autoload.php;$app = new SlimSlim();$app->get(/hello/:name, function ($name) { echo "Hello, $name";});$app->run();
    23. 23. Hello world<?phprequire ../vendor/autoload.php;$app = new SlimSlim();$app->get(/hello/:name, function ($name) { echo "Hello, $name";});$app->run();
    24. 24. Hello world<?phprequire ../vendor/autoload.php;$app = new SlimSlim();$app->get(/hello/:name, function ($name) { echo "Hello, $name";});$app->run();
    25. 25. Let’s look at aSlim application
    26. 26. Flaming Archer
    27. 27. Flaming Archer wat
    28. 28. “Great repository names are short and memorable. Need inspiration? How about flaming-archer.”
    29. 29. Flaming Archer
    30. 30. Flaming ArcherPhoto 365 project
    31. 31. Flaming ArcherPhoto 365 projectBuilt in 4 days (Saturday through Tuesday)
    32. 32. Flaming ArcherPhoto 365 projectBuilt in 4 days (Saturday through Tuesday)Basic application — a few bells, no whistles
    33. 33. Flaming ArcherPhoto 365 projectBuilt in 4 days (Saturday through Tuesday)Basic application — a few bells, no whistles Routing
    34. 34. Flaming ArcherPhoto 365 projectBuilt in 4 days (Saturday through Tuesday)Basic application — a few bells, no whistles Routing Twig views
    35. 35. Flaming ArcherPhoto 365 projectBuilt in 4 days (Saturday through Tuesday)Basic application — a few bells, no whistles Routing Twig views Middleware
    36. 36. 4 views
    37. 37. phploc --exclude vendor,tests,templates .phploc 1.6.4 by Sebastian Bergmann.Directories: 7Files: 13Lines of Code (LOC): 876 Cyclomatic Complexity / Lines of Code: 0.04Comment Lines of Code (CLOC): 272Non-Comment Lines of Code (NCLOC): 604
    38. 38. Configuration
    39. 39. return array( slim => array( templates.path => __DIR__ . /templates, log.level => 4, log.enabled => true, log.writer => new SlimExtrasLogDateTimeFileWriter( array( path => __DIR__ . /logs, name_format => y-m-d ) ) ), twig => array( // . . . ), cookies => array( // . . . ), flickr.api.key => FLICKR API KEY, pdo => array( // . . . ));
    40. 40. return array( slim => array( templates.path => __DIR__ . /templates, log.level => 4, Slim log.enabled => true, log.writer => new SlimExtrasLogDateTimeFileWriter( array( path => __DIR__ . /logs, name_format => y-m-d ) ) ), twig => array( // . . . ), cookies => array( // . . . ), flickr.api.key => FLICKR API KEY, pdo => array( // . . . ));
    41. 41. return array( slim => array( templates.path => __DIR__ . /templates, log.level => 4, Slim log.enabled => true, log.writer => new SlimExtrasLogDateTimeFileWriter( array( path => __DIR__ . /logs, name_format => y-m-d ) ) Views ), twig => array( // . . . ), cookies => array( // . . . ), flickr.api.key => FLICKR API KEY, pdo => array( // . . . ));
    42. 42. return array( slim => array( templates.path => __DIR__ . /templates, log.level => 4, Slim log.enabled => true, log.writer => new SlimExtrasLogDateTimeFileWriter( array( path => __DIR__ . /logs, name_format => y-m-d ) ) Views ), twig => array( // . . . ), cookies => array( Cookies // . . . ), flickr.api.key => FLICKR API KEY, pdo => array( // . . . ));
    43. 43. return array( slim => array( templates.path => __DIR__ . /templates, log.level => 4, Slim log.enabled => true, log.writer => new SlimExtrasLogDateTimeFileWriter( array( path => __DIR__ . /logs, name_format => y-m-d ) ) Views ), twig => array( // . . . ), cookies => array( Cookies // . . . ), flickr.api.key => FLICKR API KEY, pdo => array( // . . . ) My stuff);
    44. 44. $config = require_once __DIR__ . /../config.php;// Prepare app$app = new SlimSlim($config[slim]);
    45. 45. $config = require_once __DIR__ . /../config.php;// Prepare app$app = new SlimSlim($config[slim]); Config array goes here
    46. 46. Routing
    47. 47. Routing$app->get(/, function () use ($app, $service) { $images = $service->findAll(); $app->render(index.html, array(images => $images)); });
    48. 48. RoutingHTTP Method $app->get(/, function () use ($app, $service) { $images = $service->findAll(); $app->render(index.html, array(images => $images)); } );
    49. 49. Routing Resource URIHTTP Method $app->get(/, function () use ($app, $service) { $images = $service->findAll(); $app->render(index.html, array(images => $images)); } );
    50. 50. Routing Resource URIHTTP Method Anonymous Function $app->get(/, function () use ($app, $service) { $images = $service->findAll(); $app->render(index.html, array(images => $images)); } );
    51. 51. Routing$app->get(/, function () use ($app, $service) { $images = $service->findAll(); $app->render(index.html, array(images => $images)); });
    52. 52. Routing$app->get(/, function () use ($app, $service) { Grabs all the pics $images = $service->findAll(); $app->render(index.html, array(images => $images)); });
    53. 53. Routing$app->get(/, function () use ($app, $service) { Grabs all the pics $images = $service->findAll(); $app->render(index.html, array(images => $images)); }); Passes array of image data to index.html
    54. 54. GET$app->get(/:day, function($day) use ($app, $service) { $image = $service->find($day); if (!$image) { $app->notFound(); } $app->render(images.html, $image); })->conditions(array(day => ([1-9]d?|[12]dd|3[0-5]d|36[0-6])));
    55. 55. GET URL parameter$app->get(/:day, function($day) use ($app, $service) { $image = $service->find($day); if (!$image) { $app->notFound(); } $app->render(images.html, $image); })->conditions(array(day => ([1-9]d?|[12]dd|3[0-5]d|36[0-6])));
    56. 56. GET ... gets passed as an URL parameter argument$app->get(/:day, function($day) use ($app, $service) { $image = $service->find($day); if (!$image) { $app->notFound(); } $app->render(images.html, $image); })->conditions(array(day => ([1-9]d?|[12]dd|3[0-5]d|36[0-6])));
    57. 57. GET ... gets passed as an URL parameter argument$app->get(/:day, function($day) use ($app, $service) { $image = $service->find($day); if (!$image) { $app->notFound(); } $app->render(images.html, $image); })->conditions(array(day => ([1-9]d?|[12]dd|3[0-5]d|36[0-6]))); Condition
    58. 58. GET ... gets passed as an URL parameter argument$app->get(/:day, function($day) use ($app, $service) { $image = $service->find($day); if (!$image) { $app->notFound(); } $app->render(images.html, $image); })->conditions(array(day => ([1-9]d?|[12]dd|3[0-5]d|36[0-6]))); Condition 1 to 366
    59. 59. GET$app->get(/:day, function($day) use ($app, $service) { $image = $service->find($day); if (!$image) { $app->notFound(); 404! } $app->render(images.html, $image); })->conditions(array(day => ([1-9]d?|[12]dd|3[0-5]d|36[0-6])));
    60. 60. POST (with redirect)$app->post(/admin/add-photo, function() use ($app, $service) { $data = $app->request()->post(); $service->save($data); $app->redirect(/admin); });
    61. 61. POST (with redirect)$app->post(/admin/add-photo, function() use ($app, $service) { $data = $app->request()->post(); $service->save($data); $app->redirect(/admin); } $_POST data is in); the request object
    62. 62. POST (with redirect)$app->post(/admin/add-photo, function() use ($app, $service) { $data = $app->request()->post(); $service->save($data); $app->redirect(/admin); } $_POST data is in); the request object 302 Redirect
    63. 63. Multiple methods$app->map(/login, function() { // Login })->via(GET, POST);
    64. 64. Multiple methods Not an HTTP Method$app->map(/login, function() { // Login })->via(GET, POST);
    65. 65. Multiple methods Not an HTTP Method$app->map(/login, function() { // Login })->via(GET, POST); via() is the awesome sauce
    66. 66. Logging and flash messaging
    67. 67. $app->post(/admin/clear-cache, function() use ($app) { $log = $app->getLog(); $cleared = null; $clear = $app->request()->post(clear); if ($clear == 1) { if (apc_clear_cache(user)) { $cleared = Cache was successfully cleared!; } else { $cleared = Cache was not cleared!; $log->error(Cache not cleared); } } $app->flash(cleared, $cleared); $app->redirect(/admin); });
    68. 68. $app->post(/admin/clear-cache, function() use ($app) { $log = $app->getLog(); Get the log from $app $cleared = null; $clear = $app->request()->post(clear); if ($clear == 1) { if (apc_clear_cache(user)) { $cleared = Cache was successfully cleared!; } else { $cleared = Cache was not cleared!; $log->error(Cache not cleared); } } $app->flash(cleared, $cleared); $app->redirect(/admin); });
    69. 69. $app->post(/admin/clear-cache, function() use ($app) { $log = $app->getLog(); Get the log from $app $cleared = null; $clear = $app->request()->post(clear); if ($clear == 1) { if (apc_clear_cache(user)) { $cleared = Cache was successfully cleared!; } else { $cleared = Cache was not cleared!; $log->error(Cache not cleared); Error! } } $app->flash(cleared, $cleared); $app->redirect(/admin); });
    70. 70. $app->post(/admin/clear-cache, function() use ($app) { $log = $app->getLog(); Get the log from $app $cleared = null; $clear = $app->request()->post(clear); if ($clear == 1) { if (apc_clear_cache(user)) { $cleared = Cache was successfully cleared!; } else { $cleared = Cache was not cleared!; $log->error(Cache not cleared); Error! } } $app->flash(cleared, $cleared); Flash message available in $app->redirect(/admin); the next request. });
    71. 71. Middleware“The purpose of middleware is to inspect,analyze, or modify the applicationenvironment, request, and response beforeand/or after the Slim application isinvoked.” http://docs.slimframework.com/pages/middleware-overview/
    72. 72. Hooks
    73. 73. Hooksslim.before
    74. 74. Hooksslim.beforeslim.before.router
    75. 75. Hooksslim.beforeslim.before.routerslim.before.dispatch
    76. 76. Hooksslim.before slim.after.dispatchslim.before.routerslim.before.dispatch
    77. 77. Hooksslim.before slim.after.dispatchslim.before.router slim.after.routerslim.before.dispatch
    78. 78. Hooksslim.before slim.after.dispatchslim.before.router slim.after.routerslim.before.dispatch slim.after
    79. 79. Hooksslim.before slim.after.dispatchslim.before.router slim.after.routerslim.before.dispatch slim.after
    80. 80. class MyMiddleware extends SlimMiddleware{ public function call() { //The Slim application $app = $this->app; //The Environment object $env = $app->environment(); //The Request object $req = $app->request(); //The Response object $res = $app->response(); //Optionally call the next middleware $this->next->call(); }}
    81. 81. class MyMiddleware extends SlimMiddleware Extend this{ public function call() { //The Slim application $app = $this->app; //The Environment object $env = $app->environment(); //The Request object $req = $app->request(); //The Response object $res = $app->response(); //Optionally call the next middleware $this->next->call(); }}
    82. 82. class MyMiddleware extends SlimMiddleware Extend this{ public function call() { Define call() //The Slim application $app = $this->app; //The Environment object $env = $app->environment(); //The Request object $req = $app->request(); //The Response object $res = $app->response(); //Optionally call the next middleware $this->next->call(); }}
    83. 83. class MyMiddleware extends SlimMiddleware Extend this{ public function call() { Define call() //The Slim application $app = $this->app; //The Environment object $env = $app->environment(); Inspect, analyze, and modify! //The Request object $req = $app->request(); //The Response object $res = $app->response(); //Optionally call the next middleware $this->next->call(); }}
    84. 84. class MyMiddleware extends SlimMiddleware Extend this{ public function call() { Define call() //The Slim application $app = $this->app; //The Environment object $env = $app->environment(); Inspect, analyze, and modify! //The Request object $req = $app->request(); //The Response object $res = $app->response(); //Optionally call the next middleware $this->next->call(); On to the next! }}
    85. 85. Middleware + Hooks = WIN
    86. 86. Navigation example
    87. 87. namespace TsfMiddleware;use ZendAuthenticationAuthenticationService;class Navigation extends SlimMiddleware{ /** * @var ZendAuthenticationAuthenticationService */ private $auth; public function __construct(AuthenticationService $auth) { $this->auth = $auth; } public function call() { // . . . }}
    88. 88. namespace TsfMiddleware;use ZendAuthenticationAuthenticationService;class Navigation extends SlimMiddleware extends{ /** * @var ZendAuthenticationAuthenticationService */ private $auth; public function __construct(AuthenticationService $auth) { $this->auth = $auth; } public function call() { // . . . }}
    89. 89. namespace TsfMiddleware;use ZendAuthenticationAuthenticationService;class Navigation extends SlimMiddleware extends{ /** * @var ZendAuthenticationAuthenticationService */ private $auth; public function __construct(AuthenticationService $auth) { $this->auth = $auth; } Constructor injection public function call() FTW { // . . . }}
    90. 90. public function call(){ $app = $this->app; $auth = $this->auth; $req = $app->request(); $home = array(caption => Home, href => /); $admin = array(caption => Admin, href => /admin); $login = array(caption => Login, href => /login); $logout = array(caption => Logout, href => /logout); if ($auth->hasIdentity()) { $navigation = array($home, $admin, $logout); } else { $navigation = array($home, $login); } // . . .}
    91. 91. public function call(){ $app = $this->app; Arrays of $auth = $this->auth; nav items $req = $app->request(); $home = array(caption => Home, href => /); $admin = array(caption => Admin, href => /admin); $login = array(caption => Login, href => /login); $logout = array(caption => Logout, href => /logout); if ($auth->hasIdentity()) { $navigation = array($home, $admin, $logout); } else { $navigation = array($home, $login); } // . . .}
    92. 92. public function call(){ $app = $this->app; Arrays of $auth = $this->auth; nav items $req = $app->request(); $home = array(caption => Home, href => /); $admin = array(caption => Admin, href => /admin); $login = array(caption => Login, href => /login); $logout = array(caption => Logout, href => /logout); if ($auth->hasIdentity()) { $navigation = array($home, $admin, $logout); } else { $navigation = array($home, $login); } Nav differs based // . . . on auth status}
    93. 93. public function call(){ // . . . $this->app->hook(slim.before.router, function () use (...) { foreach ($navigation as &$link) { if ($link[href] == $req->getPath()) { $link[class] = active; } else { $link[class] = ; } } $app->view() ->appendData(array(navigation => $navigation)); } ); $this->next->call();}
    94. 94. public function call(){ Delicious hook // . . . goodness $this->app->hook(slim.before.router, function () use (...) { foreach ($navigation as &$link) { if ($link[href] == $req->getPath()) { $link[class] = active; } else { $link[class] = ; } } $app->view() ->appendData(array(navigation => $navigation)); } ); $this->next->call();}
    95. 95. public function call(){ Delicious hook // . . . goodness $this->app->hook(slim.before.router, function () use (...) { foreach ($navigation as &$link) { if ($link[href] == $req->getPath()) { $link[class] = active; } else { $link[class] = ; } Match } dispatched path $app->view() ->appendData(array(navigation => $navigation)); } ); $this->next->call();}
    96. 96. public function call(){ Delicious hook // . . . goodness $this->app->hook(slim.before.router, function () use (...) { foreach ($navigation as &$link) { if ($link[href] == $req->getPath()) { $link[class] = active; } else { $link[class] = ; } Match } dispatched path $app->view() ->appendData(array(navigation => $navigation)); } ); Append $navigation to $this->next->call();} view
    97. 97. public function call(){ Delicious hook // . . . goodness $this->app->hook(slim.before.router, function () use (...) { foreach ($navigation as &$link) { if ($link[href] == $req->getPath()) { $link[class] = active; } else { $link[class] = ; } Match } dispatched path $app->view() ->appendData(array(navigation => $navigation)); } ); Append $navigation to $this->next->call(); On to the next!} view
    98. 98. Views
    99. 99. Two great tastesthat taste great together
    100. 100. Twig
    101. 101. TwigConcise
    102. 102. TwigConciseTemplate oriented
    103. 103. TwigConciseTemplate orientedFast
    104. 104. TwigConcise Multiple inheritanceTemplate orientedFast
    105. 105. TwigConcise Multiple inheritanceTemplate oriented BlocksFast
    106. 106. TwigConcise Multiple inheritanceTemplate oriented BlocksFast Automatic escaping
    107. 107. layout.html andindex.html
    108. 108. layout.html
    109. 109. <title>{% block page_title %} {% endblock %}</title>
    110. 110. <ul class="nav"> {% for link in navigation %} <li class="{{link.class}}"> <a href="{{link.href}}">{{link.caption}}</a> </li> {% endfor %}</ul>
    111. 111. <h1>365 Days of Photography</h1><h3>Photographer: Jeremy Kendall</h3>{% block content %} {% endblock %}<hr />
    112. 112. index.html
    113. 113. {% extends layout.html %}{% block page_title %}365.jeremykendall.net{% endblock %}{% block content %}{% for image in images %}<div class="row"> <div class="span6"> <h2><a href="/{{image.day}}">{{image.day}}/365</a></h2> <p> <a href="/{{image.day}}"> <img src="{{image.sizes.size.5.source}}" /> </a> </p> <p>Posted {{image.posted|date("m/d/Y")}}</p> </div></div>{% else %}<p>No images in project</p>{% endfor %}{% endblock %}
    114. 114. {% extends layout.html %} extends{% block page_title %}365.jeremykendall.net{% endblock %}{% block content %}{% for image in images %}<div class="row"> <div class="span6"> <h2><a href="/{{image.day}}">{{image.day}}/365</a></h2> <p> <a href="/{{image.day}}"> <img src="{{image.sizes.size.5.source}}" /> </a> </p> <p>Posted {{image.posted|date("m/d/Y")}}</p> </div></div>{% else %}<p>No images in project</p>{% endfor %}{% endblock %}
    115. 115. {% extends layout.html %} extends{% block page_title %}365.jeremykendall.net{% endblock %}{% block content %} <title />{% for image in images %}<div class="row"> <div class="span6"> <h2><a href="/{{image.day}}">{{image.day}}/365</a></h2> <p> <a href="/{{image.day}}"> <img src="{{image.sizes.size.5.source}}" /> </a> </p> <p>Posted {{image.posted|date("m/d/Y")}}</p> </div></div>{% else %}<p>No images in project</p>{% endfor %}{% endblock %}
    116. 116. {% extends layout.html %} extends{% block page_title %}365.jeremykendall.net{% endblock %}{% block content %} <title />{% for image in images %}<div class="row"> <div class="span6"> <h2><a href="/{{image.day}}">{{image.day}}/365</a></h2> <p> <a href="/{{image.day}}"> <img src="{{image.sizes.size.5.source}}" /> </a> </p> <p>Posted {{image.posted|date("m/d/Y")}}</p> </div></div>{% else %}<p>No images in project</p>{% endfor %}{% endblock %}
    117. 117. {% extends layout.html %} extends{% block page_title %}365.jeremykendall.net{% endblock %}{% block content %} <title />{% for image in images %} iterator<div class="row"> <div class="span6"> <h2><a href="/{{image.day}}">{{image.day}}/365</a></h2> <p> <a href="/{{image.day}}"> <img src="{{image.sizes.size.5.source}}" /> </a> </p> <p>Posted {{image.posted|date("m/d/Y")}}</p> </div></div>{% else %}<p>No images in project</p>{% endfor %}{% endblock %}
    118. 118. {% extends layout.html %} extends{% block page_title %}365.jeremykendall.net{% endblock %}{% block content %} <title />{% for image in images %} iterator<div class="row"> <div class="span6"> <h2><a href="/{{image.day}}">{{image.day}}/365</a></h2> <p> <a href="/{{image.day}}"> <img src="{{image.sizes.size.5.source}}" /> </a> </p> <p>Posted {{image.posted|date("m/d/Y")}}</p> </div></div> else{% else %}<p>No images in project</p>{% endfor %}{% endblock %}
    119. 119. {% extends layout.html %} extends{% block page_title %}365.jeremykendall.net{% endblock %}{% block content %} <title />{% for image in images %} iterator<div class="row"> <div class="span6"> <h2><a href="/{{image.day}}">{{image.day}}/365</a></h2> <p> <a href="/{{image.day}}"> <img src="{{image.sizes.size.5.source}}" /> </a> </p> <p>Posted {{image.posted|date("m/d/Y")}}</p> </div></div> else{% else %}<p>No images in project</p> format{% endfor %}{% endblock %}
    120. 120. login.html
    121. 121. {% extends layout.html %}{% block page_title %}365.jeremykendall.net | Login{% endblock %}{% block content %}<div class="row"> <div class="span4"> <h2>Login</h2> {% if flash.error %} <p style="color: red;">{{flash.error}}</p> {% endif %} <form name="login" id="login" class="well" method="post"> // Login form . . . </form> </div></div>{% endblock %}
    122. 122. {% extends layout.html %}{% block page_title %}365.jeremykendall.net | Login{% endblock %}{% block content %}<div class="row"> <div class="span4"> <h2>Login</h2> {% if flash.error %} <p style="color: red;">{{flash.error}}</p> {% endif %} <form name="login" id="login" class="well" method="post"> // Login form . . . </form> </div></div>{% endblock %}
    123. 123. The other viewswould be redundant
    124. 124. GOTO 0
    125. 125. Small but powerful GOTO 0
    126. 126. Small but powerful GOTO 0Excellent tools to write elegant code
    127. 127. Small but powerful GOTO 0Excellent tools to write elegant codeRouting, middleware & hooks, views
    128. 128. Small but powerful GOTO 0Excellent tools to write elegant codeRouting, middleware & hooks, viewsI just scratched the surface
    129. 129. ReadSlim: slimframework.comTwig: twig.sensiolabs.orgComposer: getcomposer.orgMicroPHP Manifesto: microphp.orgFlaming Archer: http://git.io/rH0nrg
    130. 130. Questions?
    131. 131. Thanks!jeremy@jeremykendall.net @jeremykendall

    ×