SlideShare a Scribd company logo
1 of 135
Keeping it small
Getting to know the Slim micro framework
             @JeremyKendall
Jeremy
                 Kendall




raventools.com
Jeremy
                 Kendall
                 I love to code




raventools.com
Jeremy
                 Kendall
                 I love to code
                 Iā€™m terribly forgetful


raventools.com
Jeremy
                 Kendall
                 I love to code
                 Iā€™m terribly forgetful
                 I take pictures
raventools.com
Jeremy
                 Kendall
                 I love to code
                 Iā€™m terribly forgetful
                 I take pictures
raventools.com
                 I work at Raven
Micro framework?
Micro framework?

Concise codebase
Micro framework?

Concise codebase
Clear codebase
Micro framework?

Concise codebase
Clear codebase
Addresses a small set of use cases
Micro framework?

Concise codebase
Clear codebase
Addresses a small set of use cases
Addresses those use cases well
What is Slim?
What is Slim?

Inspired by Sinatra
What is Slim?

Inspired by Sinatra
Favors cleanliness over terseness
What is Slim?

Inspired by Sinatra
Favors cleanliness over terseness
Favors common cases over edge cases
Installing Slim
RTFM
RTFM ;-)
Donā€™t forget .htaccess!

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]


http://docs.slimframework.com/pages/routing-url-rewriting/
Hello world
<?php

require '../vendor/autoload.php';

$app = new SlimSlim();

$app->get('/hello/:name', function ($name) {
    echo "Hello, $name";
});

$app->run();
Hello world
<?php

require '../vendor/autoload.php';

$app = new SlimSlim();

$app->get('/hello/:name', function ($name) {
    echo "Hello, $name";
});

$app->run();
Hello world
<?php

require '../vendor/autoload.php';

$app = new SlimSlim();

$app->get('/hello/:name', function ($name) {
    echo "Hello, $name";
});

$app->run();
Hello world
<?php

require '../vendor/autoload.php';

$app = new SlimSlim();

$app->get('/hello/:name', function ($name) {
    echo "Hello, $name";
});

$app->run();
Hello world
<?php

require '../vendor/autoload.php';

$app = new SlimSlim();

$app->get('/hello/:name', function ($name) {
    echo "Hello, $name";
});

$app->run();
Letā€™s look at a
Slim application
Flaming Archer
Flaming Archer

    wat
ā€œGreat repository names are short and memorable.
 Need inspiration? How about ļ¬‚aming-archer.ā€
Flaming Archer
Flaming Archer
Photo 365 project
Flaming Archer
Photo 365 project
Built in 4 days (Saturday through Tuesday)
Flaming Archer
Photo 365 project
Built in 4 days (Saturday through Tuesday)
Basic application ā€” a few bells, no whistles
Flaming Archer
Photo 365 project
Built in 4 days (Saturday through Tuesday)
Basic application ā€” a few bells, no whistles
   Routing
Flaming Archer
Photo 365 project
Built in 4 days (Saturday through Tuesday)
Basic application ā€” a few bells, no whistles
   Routing
   Twig views
Flaming Archer
Photo 365 project
Built in 4 days (Saturday through Tuesday)
Basic application ā€” a few bells, no whistles
   Routing
   Twig views
   Middleware
4 views
phploc --exclude vendor,tests,templates .

phploc 1.6.4 by Sebastian Bergmann.

Directories:                                   7
Files:                                        13

Lines of Code (LOC):                         876
  Cyclomatic Complexity / Lines of Code:    0.04
Comment Lines of Code (CLOC):                272
Non-Comment Lines of Code (NCLOC):           604
Conļ¬guration
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(
        // . . .
    )
);
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(
        // . . .
    )
);
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(
        // . . .
    )
);
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(
        // . . .
    )
);
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
);
$config = require_once __DIR__ . '/../config.php';

// Prepare app
$app = new SlimSlim($config['slim']);
$config = require_once __DIR__ . '/../config.php';

// Prepare app
$app = new SlimSlim($config['slim']);



                        Conļ¬g array
                         goes here
Routing
Routing


$app->get('/', function () use ($app, $service) {
        $images = $service->findAll();
        $app->render('index.html', array('images' => $images));
    }
);
Routing

HTTP Method



  $app->get('/', function () use ($app, $service) {
          $images = $service->findAll();
          $app->render('index.html', array('images' => $images));
      }
  );
Routing

                   Resource URI
HTTP Method



  $app->get('/', function () use ($app, $service) {
          $images = $service->findAll();
          $app->render('index.html', array('images' => $images));
      }
  );
Routing

                   Resource URI
HTTP Method                            Anonymous Function



  $app->get('/', function () use ($app, $service) {
          $images = $service->findAll();
          $app->render('index.html', array('images' => $images));
      }
  );
Routing


$app->get('/', function () use ($app, $service) {
        $images = $service->findAll();
        $app->render('index.html', array('images' => $images));
    }
);
Routing


$app->get('/', function () use ($app, $service) {      Grabs all the pics
        $images = $service->findAll();
        $app->render('index.html', array('images' => $images));
    }
);
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
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])'));
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])'));
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])'));
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
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
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])'));
POST (with redirect)
$app->post('/admin/add-photo', function() use ($app, $service) {
        $data = $app->request()->post();
        $service->save($data);
        $app->redirect('/admin');
    }
);
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
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
Multiple methods

$app->map('/login', function() {
        // Login
    }
)->via('GET', 'POST');
Multiple methods
    Not an HTTP Method



$app->map('/login', function() {
        // Login
    }
)->via('GET', 'POST');
Multiple methods
    Not an HTTP Method



$app->map('/login', function() {
        // Login
    }
)->via('GET', 'POST');


              via() is the
            awesome sauce
Logging and ļ¬‚ash messaging
$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');
     }
);
$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');
     }
);
$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');
     }
);
$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.
     }
);
Middleware
ā€œThe purpose of middleware is to inspect,
analyze, or modify the application
environment, request, and response before
and/or after the Slim application is
invoked.ā€
 http://docs.slimframework.com/pages/middleware-overview/
Hooks
Hooks

slim.before
Hooks

slim.before
slim.before.router
Hooks

slim.before
slim.before.router
slim.before.dispatch
Hooks

slim.before            slim.after.dispatch
slim.before.router
slim.before.dispatch
Hooks

slim.before            slim.after.dispatch
slim.before.router     slim.after.router
slim.before.dispatch
Hooks

slim.before            slim.after.dispatch
slim.before.router     slim.after.router
slim.before.dispatch   slim.after
Hooks

slim.before            slim.after.dispatch
slim.before.router     slim.after.router
slim.before.dispatch   slim.after
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();
    }
}
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();
    }
}
class MyMiddleware extends SlimMiddleware            Extend this
{
    public function call()
    {                                       Deļ¬ne   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();
    }
}
class MyMiddleware extends SlimMiddleware            Extend this
{
    public function call()
    {                                       Deļ¬ne   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();
    }
}
class MyMiddleware extends SlimMiddleware            Extend this
{
    public function call()
    {                                       Deļ¬ne   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!
    }
}
Middleware + Hooks = WIN
Navigation example
namespace TsfMiddleware;

use ZendAuthenticationAuthenticationService;

class Navigation extends SlimMiddleware
{

    /**
     * @var ZendAuthenticationAuthenticationService
     */
    private $auth;

    public function __construct(AuthenticationService $auth)
    {
        $this->auth = $auth;
    }

    public function call()
    {
        // . . .
    }

}
namespace TsfMiddleware;

use ZendAuthenticationAuthenticationService;

class Navigation extends SlimMiddleware          extends
{

    /**
     * @var ZendAuthenticationAuthenticationService
     */
    private $auth;

    public function __construct(AuthenticationService $auth)
    {
        $this->auth = $auth;
    }

    public function call()
    {
        // . . .
    }

}
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
    {
        // . . .
    }

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

    // . . .
}
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);
    }

    // . . .
}
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
}
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();
}
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();
}
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();
}
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
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
Views
Two great tastes
that taste great together
Twig
Twig

Concise
Twig

Concise
Template oriented
Twig

Concise
Template oriented
Fast
Twig

Concise             Multiple inheritance
Template oriented
Fast
Twig

Concise             Multiple inheritance
Template oriented   Blocks
Fast
Twig

Concise             Multiple inheritance
Template oriented   Blocks
Fast                Automatic escaping
layout.html
    and
index.html
layout.html
<title>{% block page_title %} {% endblock %}</title>
<ul class="nav">
    {% for link in navigation %}
        <li class="{{link.class}}">
            <a href="{{link.href}}">{{link.caption}}</a>
        </li>
    {% endfor %}
</ul>
<h1>365 Days of Photography</h1>
<h3>Photographer: Jeremy Kendall</h3>
{% block content %} {% endblock %}
<hr />
index.html
{% 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 %}
{% 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 %}
{% 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 %}
{% 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 %}
{% 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 %}
{% 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 %}
{% 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 %}
login.html
{% 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 %}
{% 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 %}
The other views
would be redundant
GOTO 0
Small but powerful
                     GOTO 0
Small but powerful
                         GOTO 0
Excellent tools to write elegant code
Small but powerful
                         GOTO 0
Excellent tools to write elegant code

Routing, middleware & hooks, views
Small but powerful
                          GOTO 0
Excellent tools to write elegant code

Routing, middleware & hooks, views

I just scratched the surface
Read
Slim: slimframework.com
Twig: twig.sensiolabs.org
Composer: getcomposer.org
MicroPHP Manifesto: microphp.org
Flaming Archer: http://git.io/rH0nrg
Questions?
Thanks!

jeremy@jeremykendall.net
    @jeremykendall

More Related Content

What's hot

RESTful web services
RESTful web servicesRESTful web services
RESTful web servicesTudor Constantin
Ā 
Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojobpmedley
Ā 
Perl: Hate it for the Right Reasons
Perl: Hate it for the Right ReasonsPerl: Hate it for the Right Reasons
Perl: Hate it for the Right ReasonsMatt Follett
Ā 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony TechniquesKris Wallsmith
Ā 
Mojolicious: what works and what doesn't
Mojolicious: what works and what doesn'tMojolicious: what works and what doesn't
Mojolicious: what works and what doesn'tCosimo Streppone
Ā 
Bullet: The Functional PHP Micro-Framework
Bullet: The Functional PHP Micro-FrameworkBullet: The Functional PHP Micro-Framework
Bullet: The Functional PHP Micro-FrameworkVance Lucas
Ā 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud CastlesBen Scofield
Ā 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty HammerBen Scofield
Ā 
Mojolicious - A new hope
Mojolicious - A new hopeMojolicious - A new hope
Mojolicious - A new hopeMarcus Ramberg
Ā 
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)Dotan Dimet
Ā 
Web Apps in Perl - HTTP 101
Web Apps in Perl - HTTP 101Web Apps in Perl - HTTP 101
Web Apps in Perl - HTTP 101hendrikvb
Ā 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
Ā 
Mojolicious, real-time web framework
Mojolicious, real-time web frameworkMojolicious, real-time web framework
Mojolicious, real-time web frameworktaggg
Ā 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUGBen Scofield
Ā 
Mojolicious on Steroids
Mojolicious on SteroidsMojolicious on Steroids
Mojolicious on SteroidsTudor Constantin
Ā 
Mojolicious. Š’ŠµŠ± Š² ŠŗŠ¾Ń€Š¾Š±ŠŗŠµ!
Mojolicious. Š’ŠµŠ± Š² ŠŗŠ¾Ń€Š¾Š±ŠŗŠµ!Mojolicious. Š’ŠµŠ± Š² ŠŗŠ¾Ń€Š¾Š±ŠŗŠµ!
Mojolicious. Š’ŠµŠ± Š² ŠŗŠ¾Ń€Š¾Š±ŠŗŠµ!Anatoly Sharifulin
Ā 
Asynchronous programming patterns in Perl
Asynchronous programming patterns in PerlAsynchronous programming patterns in Perl
Asynchronous programming patterns in Perldeepfountainconsulting
Ā 
Hello World on Slim Framework 3.x
Hello World on Slim Framework 3.xHello World on Slim Framework 3.x
Hello World on Slim Framework 3.xRyan Szrama
Ā 
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupKacper Gunia
Ā 

What's hot (20)

RESTful web services
RESTful web servicesRESTful web services
RESTful web services
Ā 
Webrtc mojo
Webrtc mojoWebrtc mojo
Webrtc mojo
Ā 
Perl: Hate it for the Right Reasons
Perl: Hate it for the Right ReasonsPerl: Hate it for the Right Reasons
Perl: Hate it for the Right Reasons
Ā 
Advanced symfony Techniques
Advanced symfony TechniquesAdvanced symfony Techniques
Advanced symfony Techniques
Ā 
Mojolicious: what works and what doesn't
Mojolicious: what works and what doesn'tMojolicious: what works and what doesn't
Mojolicious: what works and what doesn't
Ā 
Bullet: The Functional PHP Micro-Framework
Bullet: The Functional PHP Micro-FrameworkBullet: The Functional PHP Micro-Framework
Bullet: The Functional PHP Micro-Framework
Ā 
Mojolicious
MojoliciousMojolicious
Mojolicious
Ā 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
Ā 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty Hammer
Ā 
Mojolicious - A new hope
Mojolicious - A new hopeMojolicious - A new hope
Mojolicious - A new hope
Ā 
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Mojolicious - Perl Framework for the Real-Time Web (Lightning Talk)
Ā 
Web Apps in Perl - HTTP 101
Web Apps in Perl - HTTP 101Web Apps in Perl - HTTP 101
Web Apps in Perl - HTTP 101
Ā 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
Ā 
Mojolicious, real-time web framework
Mojolicious, real-time web frameworkMojolicious, real-time web framework
Mojolicious, real-time web framework
Ā 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUG
Ā 
Mojolicious on Steroids
Mojolicious on SteroidsMojolicious on Steroids
Mojolicious on Steroids
Ā 
Mojolicious. Š’ŠµŠ± Š² ŠŗŠ¾Ń€Š¾Š±ŠŗŠµ!
Mojolicious. Š’ŠµŠ± Š² ŠŗŠ¾Ń€Š¾Š±ŠŗŠµ!Mojolicious. Š’ŠµŠ± Š² ŠŗŠ¾Ń€Š¾Š±ŠŗŠµ!
Mojolicious. Š’ŠµŠ± Š² ŠŗŠ¾Ń€Š¾Š±ŠŗŠµ!
Ā 
Asynchronous programming patterns in Perl
Asynchronous programming patterns in PerlAsynchronous programming patterns in Perl
Asynchronous programming patterns in Perl
Ā 
Hello World on Slim Framework 3.x
Hello World on Slim Framework 3.xHello World on Slim Framework 3.x
Hello World on Slim Framework 3.x
Ā 
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK MeetupScaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Scaling Symfony2 apps with RabbitMQ - Symfony UK Meetup
Ā 

Similar to Keeping it small: Getting to know the Slim micro framework

What mom never told you about bundle configurations - Symfony Live Paris 2012
What mom never told you about bundle configurations - Symfony Live Paris 2012What mom never told you about bundle configurations - Symfony Live Paris 2012
What mom never told you about bundle configurations - Symfony Live Paris 2012D
Ā 
関č„æPHP勉強会 php5.4ć¤ć¾ćæ恐恄
関č„æPHP勉強会 php5.4ć¤ć¾ćæćć„é–¢č„æPHP勉強会 php5.4ć¤ć¾ćæ恐恄
関č„æPHP勉強会 php5.4ć¤ć¾ćæ恐恄Hisateru Tanaka
Ā 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of DjangoJacob Kaplan-Moss
Ā 
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Ralf Eggert
Ā 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
Ā 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)tompunk
Ā 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207patter
Ā 
Apostrophe
ApostropheApostrophe
Apostrophetompunk
Ā 
RESTful API 悒 Chalice 恧ē“č§£ć 怜 Python Serverless Microframework for AWS 怜
RESTful API 悒 Chalice 恧ē“č§£ć 怜 Python Serverless Microframework for AWS 怜RESTful API 悒 Chalice 恧ē“č§£ć 怜 Python Serverless Microframework for AWS 怜
RESTful API 悒 Chalice 恧ē“č§£ć 怜 Python Serverless Microframework for AWS ć€œå“‡ä¹‹ ęø…ę°“
Ā 
Simple Photo Processing and Web Display with Perl
Simple Photo Processing and Web Display with PerlSimple Photo Processing and Web Display with Perl
Simple Photo Processing and Web Display with PerlKent Cowgill
Ā 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?Alexandru Badiu
Ā 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium AppsNate Abele
Ā 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
Ā 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Fabien Potencier
Ā 
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 FrameworksNate Abele
Ā 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
Ā 
Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3Kris Wallsmith
Ā 
Complex Sites with Silex
Complex Sites with SilexComplex Sites with Silex
Complex Sites with SilexChris Tankersley
Ā 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
Ā 

Similar to Keeping it small: Getting to know the Slim micro framework (20)

Lithium Best
Lithium Best Lithium Best
Lithium Best
Ā 
What mom never told you about bundle configurations - Symfony Live Paris 2012
What mom never told you about bundle configurations - Symfony Live Paris 2012What mom never told you about bundle configurations - Symfony Live Paris 2012
What mom never told you about bundle configurations - Symfony Live Paris 2012
Ā 
関č„æPHP勉強会 php5.4ć¤ć¾ćæ恐恄
関č„æPHP勉強会 php5.4ć¤ć¾ćæćć„é–¢č„æPHP勉強会 php5.4ć¤ć¾ćæ恐恄
関č„æPHP勉強会 php5.4ć¤ć¾ćæ恐恄
Ā 
The Best (and Worst) of Django
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of Django
Ā 
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Drehbuch zum Talk "Rapid Prototyping mit PHP Frameworks"
Ā 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
Ā 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)
Ā 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
Ā 
Apostrophe
ApostropheApostrophe
Apostrophe
Ā 
RESTful API 悒 Chalice 恧ē“č§£ć 怜 Python Serverless Microframework for AWS 怜
RESTful API 悒 Chalice 恧ē“č§£ć 怜 Python Serverless Microframework for AWS 怜RESTful API 悒 Chalice 恧ē“č§£ć 怜 Python Serverless Microframework for AWS 怜
RESTful API 悒 Chalice 恧ē“č§£ć 怜 Python Serverless Microframework for AWS 怜
Ā 
Simple Photo Processing and Web Display with Perl
Simple Photo Processing and Web Display with PerlSimple Photo Processing and Web Display with Perl
Simple Photo Processing and Web Display with Perl
Ā 
What's new in the Drupal 7 API?
What's new in the Drupal 7 API?What's new in the Drupal 7 API?
What's new in the Drupal 7 API?
Ā 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
Ā 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
Ā 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
Ā 
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
Ā 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
Ā 
Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3
Ā 
Complex Sites with Silex
Complex Sites with SilexComplex Sites with Silex
Complex Sites with Silex
Ā 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
Ā 

More from Jeremy Kendall

Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPJeremy Kendall
Ā 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPJeremy Kendall
Ā 
5 Ways to Awesome-ize Your (PHP) Code
5 Ways to Awesome-ize Your (PHP) Code5 Ways to Awesome-ize Your (PHP) Code
5 Ways to Awesome-ize Your (PHP) CodeJeremy Kendall
Ā 
Game Changing Dependency Management
Game Changing Dependency ManagementGame Changing Dependency Management
Game Changing Dependency ManagementJeremy Kendall
Ā 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodJeremy Kendall
Ā 
PHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the GoodPHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the GoodJeremy Kendall
Ā 
Intro to #memtech PHP 2011-12-05
Intro to #memtech PHP   2011-12-05Intro to #memtech PHP   2011-12-05
Intro to #memtech PHP 2011-12-05Jeremy Kendall
Ā 
TDD in PHP - Memphis PHP 2011-08-25
TDD in PHP - Memphis PHP 2011-08-25TDD in PHP - Memphis PHP 2011-08-25
TDD in PHP - Memphis PHP 2011-08-25Jeremy Kendall
Ā 
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_FormZend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_FormJeremy Kendall
Ā 
Zero to ZF in 10 Minutes
Zero to ZF in 10 MinutesZero to ZF in 10 Minutes
Zero to ZF in 10 MinutesJeremy Kendall
Ā 
Tdd in php a brief example
Tdd in php   a brief exampleTdd in php   a brief example
Tdd in php a brief exampleJeremy Kendall
Ā 
A Brief Introduction to Zend_Form
A Brief Introduction to Zend_FormA Brief Introduction to Zend_Form
A Brief Introduction to Zend_FormJeremy Kendall
Ā 
Zero to Zend Framework in 10 minutes
Zero to Zend Framework in 10 minutesZero to Zend Framework in 10 minutes
Zero to Zend Framework in 10 minutesJeremy Kendall
Ā 

More from Jeremy Kendall (14)

Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHP
Ā 
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHPLeveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHP
Ā 
5 Ways to Awesome-ize Your (PHP) Code
5 Ways to Awesome-ize Your (PHP) Code5 Ways to Awesome-ize Your (PHP) Code
5 Ways to Awesome-ize Your (PHP) Code
Ā 
Game Changing Dependency Management
Game Changing Dependency ManagementGame Changing Dependency Management
Game Changing Dependency Management
Ā 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the Good
Ā 
Php 101: PDO
Php 101: PDOPhp 101: PDO
Php 101: PDO
Ā 
PHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the GoodPHP 102: Out with the Bad, In with the Good
PHP 102: Out with the Bad, In with the Good
Ā 
Intro to #memtech PHP 2011-12-05
Intro to #memtech PHP   2011-12-05Intro to #memtech PHP   2011-12-05
Intro to #memtech PHP 2011-12-05
Ā 
TDD in PHP - Memphis PHP 2011-08-25
TDD in PHP - Memphis PHP 2011-08-25TDD in PHP - Memphis PHP 2011-08-25
TDD in PHP - Memphis PHP 2011-08-25
Ā 
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_FormZend_Form to the Rescue - A Brief Introduction to Zend_Form
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
Ā 
Zero to ZF in 10 Minutes
Zero to ZF in 10 MinutesZero to ZF in 10 Minutes
Zero to ZF in 10 Minutes
Ā 
Tdd in php a brief example
Tdd in php   a brief exampleTdd in php   a brief example
Tdd in php a brief example
Ā 
A Brief Introduction to Zend_Form
A Brief Introduction to Zend_FormA Brief Introduction to Zend_Form
A Brief Introduction to Zend_Form
Ā 
Zero to Zend Framework in 10 minutes
Zero to Zend Framework in 10 minutesZero to Zend Framework in 10 minutes
Zero to Zend Framework in 10 minutes
Ā 

Recently uploaded

FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | DelhiFULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhisoniya singh
Ā 
#StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024BookNet Canada
Ā 
SIEMENS: RAPUNZEL ā€“ A Tale About Knowledge Graph
SIEMENS: RAPUNZEL ā€“ A Tale About Knowledge GraphSIEMENS: RAPUNZEL ā€“ A Tale About Knowledge Graph
SIEMENS: RAPUNZEL ā€“ A Tale About Knowledge GraphNeo4j
Ā 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
Ā 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
Ā 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
Ā 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
Ā 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
Ā 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
Ā 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Hyundai Motor Group
Ā 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
Ā 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
Ā 
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024BookNet Canada
Ā 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
Ā 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
Ā 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
Ā 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
Ā 
Swan(sea) Song ā€“ personal research during my six years at Swansea ... and bey...
Swan(sea) Song ā€“ personal research during my six years at Swansea ... and bey...Swan(sea) Song ā€“ personal research during my six years at Swansea ... and bey...
Swan(sea) Song ā€“ personal research during my six years at Swansea ... and bey...Alan Dix
Ā 
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
Ā 

Recently uploaded (20)

FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | DelhiFULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY šŸ” 8264348440 šŸ” Call Girls in Diplomatic Enclave | Delhi
Ā 
#StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Ā 
SIEMENS: RAPUNZEL ā€“ A Tale About Knowledge Graph
SIEMENS: RAPUNZEL ā€“ A Tale About Knowledge GraphSIEMENS: RAPUNZEL ā€“ A Tale About Knowledge Graph
SIEMENS: RAPUNZEL ā€“ A Tale About Knowledge Graph
Ā 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
Ā 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Ā 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
Ā 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
Ā 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
Ā 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
Ā 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2
Ā 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
Ā 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Ā 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
Ā 
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: Whatā€™s new for BISAC - Tech Forum 2024
Ā 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
Ā 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
Ā 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
Ā 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
Ā 
Swan(sea) Song ā€“ personal research during my six years at Swansea ... and bey...
Swan(sea) Song ā€“ personal research during my six years at Swansea ... and bey...Swan(sea) Song ā€“ personal research during my six years at Swansea ... and bey...
Swan(sea) Song ā€“ personal research during my six years at Swansea ... and bey...
Ā 
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 āœ“Call Girls In Kalyan ( Mumbai ) secure service
Ā 

Keeping it small: Getting to know the Slim micro framework

  • 1. Keeping it small Getting to know the Slim micro framework @JeremyKendall
  • 2. Jeremy Kendall raventools.com
  • 3. Jeremy Kendall I love to code raventools.com
  • 4. Jeremy Kendall I love to code Iā€™m terribly forgetful raventools.com
  • 5. Jeremy Kendall I love to code Iā€™m terribly forgetful I take pictures raventools.com
  • 6. Jeremy Kendall I love to code Iā€™m terribly forgetful I take pictures raventools.com I work at Raven
  • 10. Micro framework? Concise codebase Clear codebase Addresses a small set of use cases
  • 11. Micro framework? Concise codebase Clear codebase Addresses a small set of use cases Addresses those use cases well
  • 14. What is Slim? Inspired by Sinatra Favors cleanliness over terseness
  • 15. What is Slim? Inspired by Sinatra Favors cleanliness over terseness Favors common cases over edge cases
  • 17. RTFM
  • 19. Donā€™t forget .htaccess! RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [QSA,L] http://docs.slimframework.com/pages/routing-url-rewriting/
  • 20. Hello world <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run();
  • 21. Hello world <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run();
  • 22. Hello world <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run();
  • 23. Hello world <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run();
  • 24. Hello world <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run();
  • 25. Letā€™s look at a Slim application
  • 28. ā€œGreat repository names are short and memorable. Need inspiration? How about ļ¬‚aming-archer.ā€
  • 31. Flaming Archer Photo 365 project Built in 4 days (Saturday through Tuesday)
  • 32. Flaming Archer Photo 365 project Built in 4 days (Saturday through Tuesday) Basic application ā€” a few bells, no whistles
  • 33. Flaming Archer Photo 365 project Built in 4 days (Saturday through Tuesday) Basic application ā€” a few bells, no whistles Routing
  • 34. Flaming Archer Photo 365 project Built in 4 days (Saturday through Tuesday) Basic application ā€” a few bells, no whistles Routing Twig views
  • 35. Flaming Archer Photo 365 project Built in 4 days (Saturday through Tuesday) Basic application ā€” a few bells, no whistles Routing Twig views Middleware
  • 37.
  • 38.
  • 39.
  • 40.
  • 41. phploc --exclude vendor,tests,templates . phploc 1.6.4 by Sebastian Bergmann. Directories: 7 Files: 13 Lines of Code (LOC): 876 Cyclomatic Complexity / Lines of Code: 0.04 Comment Lines of Code (CLOC): 272 Non-Comment Lines of Code (NCLOC): 604
  • 43. 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( // . . . ) );
  • 44. 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( // . . . ) );
  • 45. 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( // . . . ) );
  • 46. 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( // . . . ) );
  • 47. 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 );
  • 48. $config = require_once __DIR__ . '/../config.php'; // Prepare app $app = new SlimSlim($config['slim']);
  • 49. $config = require_once __DIR__ . '/../config.php'; // Prepare app $app = new SlimSlim($config['slim']); Conļ¬g array goes here
  • 51. Routing $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } );
  • 52. Routing HTTP Method $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } );
  • 53. Routing Resource URI HTTP Method $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } );
  • 54. Routing Resource URI HTTP Method Anonymous Function $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } );
  • 55. Routing $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } );
  • 56. Routing $app->get('/', function () use ($app, $service) { Grabs all the pics $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } );
  • 57. 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
  • 58. 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])'));
  • 59. 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])'));
  • 60. 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])'));
  • 61. 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
  • 62. 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
  • 63. 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])'));
  • 64. POST (with redirect) $app->post('/admin/add-photo', function() use ($app, $service) { $data = $app->request()->post(); $service->save($data); $app->redirect('/admin'); } );
  • 65. 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
  • 66. 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
  • 67. Multiple methods $app->map('/login', function() { // Login } )->via('GET', 'POST');
  • 68. Multiple methods Not an HTTP Method $app->map('/login', function() { // Login } )->via('GET', 'POST');
  • 69. Multiple methods Not an HTTP Method $app->map('/login', function() { // Login } )->via('GET', 'POST'); via() is the awesome sauce
  • 71. $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'); } );
  • 72. $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'); } );
  • 73. $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'); } );
  • 74. $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. } );
  • 75. Middleware ā€œThe purpose of middleware is to inspect, analyze, or modify the application environment, request, and response before and/or after the Slim application is invoked.ā€ http://docs.slimframework.com/pages/middleware-overview/
  • 76. Hooks
  • 80. Hooks slim.before slim.after.dispatch slim.before.router slim.before.dispatch
  • 81. Hooks slim.before slim.after.dispatch slim.before.router slim.after.router slim.before.dispatch
  • 82. Hooks slim.before slim.after.dispatch slim.before.router slim.after.router slim.before.dispatch slim.after
  • 83. Hooks slim.before slim.after.dispatch slim.before.router slim.after.router slim.before.dispatch slim.after
  • 84. 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(); } }
  • 85. 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(); } }
  • 86. class MyMiddleware extends SlimMiddleware Extend this { public function call() { Deļ¬ne 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(); } }
  • 87. class MyMiddleware extends SlimMiddleware Extend this { public function call() { Deļ¬ne 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(); } }
  • 88. class MyMiddleware extends SlimMiddleware Extend this { public function call() { Deļ¬ne 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! } }
  • 91. namespace TsfMiddleware; use ZendAuthenticationAuthenticationService; class Navigation extends SlimMiddleware { /** * @var ZendAuthenticationAuthenticationService */ private $auth; public function __construct(AuthenticationService $auth) { $this->auth = $auth; } public function call() { // . . . } }
  • 92. namespace TsfMiddleware; use ZendAuthenticationAuthenticationService; class Navigation extends SlimMiddleware extends { /** * @var ZendAuthenticationAuthenticationService */ private $auth; public function __construct(AuthenticationService $auth) { $this->auth = $auth; } public function call() { // . . . } }
  • 93. 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 { // . . . } }
  • 94. 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); } // . . . }
  • 95. 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); } // . . . }
  • 96. 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 }
  • 97. 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(); }
  • 98. 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(); }
  • 99. 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(); }
  • 100. 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
  • 101. 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
  • 102. Views
  • 103. Two great tastes that taste great together
  • 104. Twig
  • 108. Twig Concise Multiple inheritance Template oriented Fast
  • 109. Twig Concise Multiple inheritance Template oriented Blocks Fast
  • 110. Twig Concise Multiple inheritance Template oriented Blocks Fast Automatic escaping
  • 111. layout.html and index.html
  • 113. <title>{% block page_title %} {% endblock %}</title>
  • 114. <ul class="nav"> {% for link in navigation %} <li class="{{link.class}}"> <a href="{{link.href}}">{{link.caption}}</a> </li> {% endfor %} </ul>
  • 115. <h1>365 Days of Photography</h1> <h3>Photographer: Jeremy Kendall</h3> {% block content %} {% endblock %} <hr />
  • 117. {% 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 %}
  • 118. {% 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 %}
  • 119. {% 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 %}
  • 120. {% 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 %}
  • 121. {% 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 %}
  • 122. {% 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 %}
  • 123. {% 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 %}
  • 125. {% 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 %}
  • 126. {% 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 %}
  • 127. The other views would be redundant
  • 128. GOTO 0
  • 130. Small but powerful GOTO 0 Excellent tools to write elegant code
  • 131. Small but powerful GOTO 0 Excellent tools to write elegant code Routing, middleware & hooks, views
  • 132. Small but powerful GOTO 0 Excellent tools to write elegant code Routing, middleware & hooks, views I just scratched the surface
  • 133. Read Slim: slimframework.com Twig: twig.sensiolabs.org Composer: getcomposer.org MicroPHP Manifesto: microphp.org Flaming Archer: http://git.io/rH0nrg

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. WTF?\n
  25. Blame it on github and their repo name suggetsions\n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. Four views\n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. Can be anything that returns true for is_callable()\n\n
  46. Can be anything that returns true for is_callable()\n\n
  47. Can be anything that returns true for is_callable()\n\n
  48. Can be anything that returns true for is_callable()\n\n
  49. Can be anything that returns true for is_callable()\n\n
  50. Can be anything that returns true for is_callable()\n\n
  51. Can be anything that returns true for is_callable()\n\n
  52. Can be anything that returns true for is_callable()\n\n
  53. GET, including route parameters and conditions\n
  54. GET, including route parameters and conditions\n
  55. GET, including route parameters and conditions\n
  56. GET, including route parameters and conditions\n
  57. GET, including route parameters and conditions\n
  58. GET, including route parameters and conditions\n
  59. GET, including route parameters and conditions\n
  60. GET, including route parameters and conditions\n
  61. GET, including route parameters and conditions\n
  62. GET, including route parameters and conditions\n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  73. slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  74. slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  75. slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  76. slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  77. slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  78. slim.before.router: after output buffering is turned on and before the router is dispatched. Once.\n\n
  79. Has access to app, environment, request &amp; response object\n
  80. Has access to app, environment, request &amp; response object\n
  81. Has access to app, environment, request &amp; response object\n
  82. Has access to app, environment, request &amp; response object\n
  83. Has access to app, environment, request &amp; response object\n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. I won&amp;#x2019;t cover bootstrap, but it kicks ass\n
  96. \n
  97. \n
  98. \n
  99. \n
  100. \n
  101. \n
  102. Too much boilerplate to show off, but here come the important parts\n
  103. \n
  104. \n
  105. \n
  106. \n
  107. \n
  108. \n
  109. \n
  110. \n
  111. \n
  112. \n
  113. \n
  114. \n
  115. \n
  116. \n
  117. \n
  118. \n
  119. \n
  120. \n
  121. \n
  122. \n
  123. \n
  124. \n