SlideShare une entreprise Scribd logo
1  sur  214
Télécharger pour lire hors ligne
Keeping it small
Getting to know the Slim micro framework
php[tek] 2013
Wednesday, May 15, 13
Wednesday, May 15, 13
I love to code
Wednesday, May 15, 13
I love to code
I’m terribly forgetful
Wednesday, May 15, 13
I love to code
I’m terribly forgetful
I take pictures
Wednesday, May 15, 13
I love to code
I’m terribly forgetful
I take pictures
I work at OpenSky
Wednesday, May 15, 13
Micro framework?
Wednesday, May 15, 13
MicroPHP Manifesto
Wednesday, May 15, 13
MicroPHP Manifesto
Written by Ed Finkler
Wednesday, May 15, 13
MicroPHP Manifesto
Written by Ed Finkler
Punk rock vs. Prog rock
Wednesday, May 15, 13
MicroPHP Manifesto
Written by Ed Finkler
Punk rock vs. Prog rock
Prophet or Madman?
Wednesday, May 15, 13
MicroPHP Manifesto
Written by Ed Finkler
Punk rock vs. Prog rock
Prophet or Madman?
Guiding principle
Wednesday, May 15, 13
MicroPHP Manifesto
Written by Ed Finkler
Punk rock vs. Prog rock
Prophet or Madman?
Guiding principle
http://microphp.org/
Wednesday, May 15, 13
Micro framework?
Wednesday, May 15, 13
Micro framework?
Concise codebase
Wednesday, May 15, 13
Micro framework?
Concise codebase
Clear codebase
Wednesday, May 15, 13
Micro framework?
Concise codebase
Clear codebase
Addresses a small set of use cases
Wednesday, May 15, 13
Micro framework?
Concise codebase
Clear codebase
Addresses a small set of use cases
Addresses those use cases well
Wednesday, May 15, 13
I chose Slim PHP
Wednesday, May 15, 13
I chose Slim PHP
and I sucked at it
Wednesday, May 15, 13
What is Slim?
Wednesday, May 15, 13
What is Slim?
Inspired by Sinatra
Wednesday, May 15, 13
What is Slim?
Inspired by Sinatra
Favors cleanliness over terseness
Wednesday, May 15, 13
What is Slim?
Inspired by Sinatra
Favors cleanliness over terseness
Favors common cases over edge cases
Wednesday, May 15, 13
Installing Slim
Wednesday, May 15, 13
Install Composer
curl -s https://getcomposer.org/installer | php
Wednesday, May 15, 13
Install Composer
curl -s https://getcomposer.org/installer | php
If you take nothing else away from this talk, I hope that
it’s Composer. It’s that big of a deal.
Wednesday, May 15, 13
composer.json
{
"require": {
"slim/slim": "2.*"
}
}
Wednesday, May 15, 13
Install via Composer
php composer.phar install
Wednesday, May 15, 13
Add this to index.php
<?php
require 'vendor/autoload.php';
Wednesday, May 15, 13
Pro tip
mv composer.phar /usr/local/bin/composer
Wednesday, May 15, 13
Don’t forget .htaccess!
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
http://docs.slimframework.com/#Route-URL-Rewriting
(nginx documentation available at same URL)
Wednesday, May 15, 13
Hello $name
<?php
require '../vendor/autoload.php';
$app = new SlimSlim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name";
});
$app->run();
Wednesday, May 15, 13
Hello $name
<?php
require '../vendor/autoload.php';
$app = new SlimSlim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name";
});
$app->run();
Wednesday, May 15, 13
Hello $name
<?php
require '../vendor/autoload.php';
$app = new SlimSlim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name";
});
$app->run();
Wednesday, May 15, 13
Hello $name
<?php
require '../vendor/autoload.php';
$app = new SlimSlim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name";
});
$app->run();
Wednesday, May 15, 13
Hello $name
<?php
require '../vendor/autoload.php';
$app = new SlimSlim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name";
});
$app->run();
Wednesday, May 15, 13
Getting there
http://localhost/index.php/hello/tek
OR
http://localhost/hello/tek
Wednesday, May 15, 13
Slim in practice
Wednesday, May 15, 13
Flaming Archer!
Wednesday, May 15, 13
“Great repository names are short and memorable.
Need inspiration? How about flaming-archer.”
Wednesday, May 15, 13
Flaming Archer
Wednesday, May 15, 13
Flaming Archer
Photo 365 project
Wednesday, May 15, 13
Flaming Archer
Photo 365 project
Bulk of app built in 4 days
Wednesday, May 15, 13
Flaming Archer
Photo 365 project
Bulk of app built in 4 days
Basic application — a few bells, no whistles
Wednesday, May 15, 13
Flaming Archer
Photo 365 project
Bulk of app built in 4 days
Basic application — a few bells, no whistles
Routing
Wednesday, May 15, 13
Flaming Archer
Photo 365 project
Bulk of app built in 4 days
Basic application — a few bells, no whistles
Routing
Twig templates
Wednesday, May 15, 13
Flaming Archer
Photo 365 project
Bulk of app built in 4 days
Basic application — a few bells, no whistles
Routing
Twig templates
Middleware
Wednesday, May 15, 13
Flaming Archer
Photo 365 project
Bulk of app built in 4 days
Basic application — a few bells, no whistles
Routing
Twig templates
Middleware
Hooks
Wednesday, May 15, 13
4 views
Wednesday, May 15, 13
Wednesday, May 15, 13
Wednesday, May 15, 13
Wednesday, May 15, 13
Wednesday, May 15, 13
phploc --exclude vendor --exclude tests --exclude templates .
phploc 1.7.4 by Sebastian Bergmann.
Directories: 8
Files: 16
Lines of Code (LOC): 1212
Cyclomatic Complexity / Lines of Code: 0.03
Comment Lines of Code (CLOC): 453
Non-Comment Lines of Code (NCLOC): 759
Wednesday, May 15, 13
Configuration
Wednesday, May 15, 13
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(
// . . .
)
);
Wednesday, May 15, 13
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(
// . . .
)
);
Slim
Wednesday, May 15, 13
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(
// . . .
)
);
Slim
Views
Wednesday, May 15, 13
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(
// . . .
)
);
Slim
Views
Cookies
Wednesday, May 15, 13
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(
// . . .
)
);
Slim
Views
Cookies
App specific
Wednesday, May 15, 13
$config = require_once __DIR__ . '/../config.php';
// Prepare app
$app = new SlimSlim($config['slim']);
Configuration
Wednesday, May 15, 13
$config = require_once __DIR__ . '/../config.php';
// Prepare app
$app = new SlimSlim($config['slim']);
Config array
goes here
Configuration
Wednesday, May 15, 13
Routing
Wednesday, May 15, 13
Routing
$app->get('/', function () use ($app, $service) {
$images = $service->findAll();
$app->render('index.html', array('images' => $images));
}
);
Wednesday, May 15, 13
Routing
$app->get('/', function () use ($app, $service) {
$images = $service->findAll();
$app->render('index.html', array('images' => $images));
}
);
HTTP Method
Wednesday, May 15, 13
Routing
$app->get('/', function () use ($app, $service) {
$images = $service->findAll();
$app->render('index.html', array('images' => $images));
}
);
HTTP Method
Resource URI
Wednesday, May 15, 13
Routing
$app->get('/', function () use ($app, $service) {
$images = $service->findAll();
$app->render('index.html', array('images' => $images));
}
);
HTTP Method
Resource URI
Anonymous Function
Wednesday, May 15, 13
Routing
$app->get('/', function () use ($app, $service) {
$images = $service->findAll();
$app->render('index.html', array('images' => $images));
}
);
Wednesday, May 15, 13
Routing
$app->get('/', function () use ($app, $service) {
$images = $service->findAll();
$app->render('index.html', array('images' => $images));
}
);
Grabs all the pics
Wednesday, May 15, 13
Routing
$app->get('/', function () use ($app, $service) {
$images = $service->findAll();
$app->render('index.html', array('images' => $images));
}
);
Grabs all the pics
Passes array of image data to index.html
Wednesday, May 15, 13
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])'));
Wednesday, May 15, 13
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])'));
URL parameter
Wednesday, May 15, 13
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])'));
URL parameter
... gets passed as an
argument
Wednesday, May 15, 13
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])'));
URL parameter
... gets passed as an
argument
Condition
Wednesday, May 15, 13
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])'));
URL parameter
... gets passed as an
argument
Condition 1 to 366
Wednesday, May 15, 13
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])'));
404!
Wednesday, May 15, 13
POST (with redirect)
$app->post('/admin/add-photo', function() use ($app, $service) {
$data = $app->request()->post();
$service->save($data);
$app->redirect('/admin');
}
);
Wednesday, May 15, 13
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
Wednesday, May 15, 13
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
Wednesday, May 15, 13
Multiple methods
$app->map('/login', function() {
// Login
}
)->via('GET', 'POST');
Wednesday, May 15, 13
Multiple methods
$app->map('/login', function() {
// Login
}
)->via('GET', 'POST');
Not an HTTP Method
Wednesday, May 15, 13
Multiple methods
$app->map('/login', function() {
// Login
}
)->via('GET', 'POST');
Not an HTTP Method
via() is the
awesome sauce
Wednesday, May 15, 13
Logging and flash messaging
Wednesday, May 15, 13
$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');
}
);
Wednesday, May 15, 13
$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');
}
);
Get the log from $app
Wednesday, May 15, 13
$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');
}
);
Get the log from $app
Error!
Wednesday, May 15, 13
$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');
}
);
Get the log from $app
Error!
Flash message available in
the next request.
Wednesday, May 15, 13
Middleware
“. . . a Slim application can have middleware
that may inspect, analyze, or modify
the application environment, request, and
response before and/or after the Slim
application is invoked.”
http://docs.slimframework.com/#Middleware-Overview
Wednesday, May 15, 13
Middleware
Wednesday, May 15, 13
Middleware
Like layers of an onion
Wednesday, May 15, 13
Middleware
Like layers of an onion
The Slim application is the core of the onion
Wednesday, May 15, 13
Middleware
Like layers of an onion
The Slim application is the core of the onion
Each new middleware wraps any existing middleware
Wednesday, May 15, 13
Middleware
Like layers of an onion
The Slim application is the core of the onion
Each new middleware wraps any existing middleware
Each middleware optionally calls the next middleware in
the chain
Wednesday, May 15, 13
Middleware
Like layers of an onion
The Slim application is the core of the onion
Each new middleware wraps any existing middleware
Each middleware optionally calls the next middleware in
the chain
Middleware is executed from the outside in
Wednesday, May 15, 13
Middleware
Like layers of an onion
The Slim application is the core of the onion
Each new middleware wraps any existing middleware
Each middleware optionally calls the next middleware in
the chain
Middleware is executed from the outside in
Pay careful attention to the order in which you register
middleware
Wednesday, May 15, 13
Middleware
// Prepare app
$app = new SlimSlim($config['slim']);
// . . .
$app->add(new Navigation($auth));
$app->add(new Authentication($auth, $config));
Wednesday, May 15, 13
Middleware
// Prepare app
$app = new SlimSlim($config['slim']);
// . . .
$app->add(new Navigation($auth));
$app->add(new Authentication($auth, $config));
Wednesday, May 15, 13
Middleware
// Prepare app
$app = new SlimSlim($config['slim']);
// . . .
$app->add(new Navigation($auth));
$app->add(new Authentication($auth, $config));
Wednesday, May 15, 13
Existing Middleware
Wednesday, May 15, 13
Existing Middleware
Flash messaging
Wednesday, May 15, 13
Existing Middleware
Flash messaging
Content types
Wednesday, May 15, 13
Existing Middleware
Flash messaging
Content types
Pretty exceptions
Wednesday, May 15, 13
Existing Middleware
Flash messaging
Content types
Pretty exceptions
Session cookie
Wednesday, May 15, 13
Existing Middleware
Flash messaging
Content types
Pretty exceptions
Session cookie
More in Slim Extras
Wednesday, May 15, 13
Roll your own Middleware
Wednesday, May 15, 13
Roll your own Middleware
Super easy
Wednesday, May 15, 13
Roll your own Middleware
Super easy
DRYs up code
Wednesday, May 15, 13
Roll your own Middleware
Super easy
DRYs up code
Awesome application wide functionality
Wednesday, May 15, 13
Roll your own Middleware
Super easy
DRYs up code
Awesome application wide functionality
Just extend SlimMiddleware and implement call()
Wednesday, May 15, 13
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();
}
}
Wednesday, May 15, 13
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();
}
}
Extend this
Wednesday, May 15, 13
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();
}
}
Extend this
Define call()
Wednesday, May 15, 13
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();
}
}
Extend this
Define call()
Inspect, analyze,
and modify!
Wednesday, May 15, 13
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();
}
}
Extend this
Define call()
On to the next!
Inspect, analyze,
and modify!
Wednesday, May 15, 13
Navigation example
Wednesday, May 15, 13
namespace FaMiddleware;
use ZendAuthenticationAuthenticationService;
class Navigation extends SlimMiddleware
{
/** @var AuthenticationService */
private $auth;
public function __construct(AuthenticationService $auth)
{
$this->auth = $auth;
}
public function call()
{
// . . .
}
}
Wednesday, May 15, 13
namespace FaMiddleware;
use ZendAuthenticationAuthenticationService;
class Navigation extends SlimMiddleware
{
/** @var AuthenticationService */
private $auth;
public function __construct(AuthenticationService $auth)
{
$this->auth = $auth;
}
public function call()
{
// . . .
}
}
extends
Wednesday, May 15, 13
namespace FaMiddleware;
use ZendAuthenticationAuthenticationService;
class Navigation extends SlimMiddleware
{
/** @var AuthenticationService */
private $auth;
public function __construct(AuthenticationService $auth)
{
$this->auth = $auth;
}
public function call()
{
// . . .
}
}
Constructor injection
FTW
extends
Wednesday, May 15, 13
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);
}
// . . .
}
Wednesday, May 15, 13
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);
}
// . . .
}
Arrays of
nav items
Wednesday, May 15, 13
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);
}
// . . .
}
Arrays of
nav items
Nav differs based
on auth status
Wednesday, May 15, 13
public function call()
{
// . . .
foreach ($navigation as &$link) {
if ($link['href'] == $req->getPath()) {
$link['class'] = 'active';
} else {
$link['class'] = '';
}
}
$app->view()->appendData(array('navigation' => $navigation));
$this->next->call();
}
Wednesday, May 15, 13
public function call()
{
// . . .
foreach ($navigation as &$link) {
if ($link['href'] == $req->getPath()) {
$link['class'] = 'active';
} else {
$link['class'] = '';
}
}
$app->view()->appendData(array('navigation' => $navigation));
$this->next->call();
}
Match
dispatched path
Wednesday, May 15, 13
public function call()
{
// . . .
foreach ($navigation as &$link) {
if ($link['href'] == $req->getPath()) {
$link['class'] = 'active';
} else {
$link['class'] = '';
}
}
$app->view()->appendData(array('navigation' => $navigation));
$this->next->call();
}
Match
dispatched path
Append
$navigation to
view
Wednesday, May 15, 13
public function call()
{
// . . .
foreach ($navigation as &$link) {
if ($link['href'] == $req->getPath()) {
$link['class'] = 'active';
} else {
$link['class'] = '';
}
}
$app->view()->appendData(array('navigation' => $navigation));
$this->next->call();
}
Match
dispatched path
Append
$navigation to
view
On to the next!
Wednesday, May 15, 13
Route Middleware
Wednesday, May 15, 13
Route Middleware
Anything that returns true for is_callable()
Wednesday, May 15, 13
Route Middleware
Anything that returns true for is_callable()
Apply directly to route!
Wednesday, May 15, 13
Route Middleware
Anything that returns true for is_callable()
Apply directly to route!
Goes between route definition and route callable
Wednesday, May 15, 13
Route Middleware
<?php
function mw1() {
echo "This is middleware!";
}
function mw2() {
echo "This is middleware!";
}
$app = new SlimSlim();
$app->get('/foo', 'mw1', 'mw2', function () {
//Do something
});
http://docs.slimframework.com/#Route-Middleware
Wednesday, May 15, 13
Route Middleware
<?php
function mw1() {
echo "This is middleware!";
}
function mw2() {
echo "This is middleware!";
}
$app = new SlimSlim();
$app->get('/foo', 'mw1', 'mw2', function () {
//Do something
});
http://docs.slimframework.com/#Route-Middleware
Wednesday, May 15, 13
Hooks
A “hook” is a moment in the Slim application lifecycle
at which a priority list of callables assigned to the
hook will be invoked.A hook is identified by a string
name.
http://docs.slimframework.com/#Hooks-Overview
Wednesday, May 15, 13
Hooks
Wednesday, May 15, 13
Hooks
Anything that returns true for is_callable()
Wednesday, May 15, 13
Hooks
Anything that returns true for is_callable()
Prioritized
Wednesday, May 15, 13
Hooks
Anything that returns true for is_callable()
Prioritized
Six default hooks
Wednesday, May 15, 13
Hooks
Wednesday, May 15, 13
slim.before
Hooks
Wednesday, May 15, 13
slim.before
slim.before.router
Hooks
Wednesday, May 15, 13
slim.before
slim.before.router
slim.before.dispatch
Hooks
Wednesday, May 15, 13
slim.before
slim.before.router
slim.before.dispatch
slim.after.dispatch
Hooks
Wednesday, May 15, 13
slim.before
slim.before.router
slim.before.dispatch
slim.after.dispatch
slim.after.router
Hooks
Wednesday, May 15, 13
slim.before
slim.before.router
slim.before.dispatch
slim.after.dispatch
slim.after.router
slim.after
Hooks
Wednesday, May 15, 13
slim.before
slim.before.router
slim.before.dispatch
slim.after.dispatch
slim.after.router
slim.after
Hooks
Wednesday, May 15, 13
Hooks
$app = new SlimSlim();
$app->hook('the.hook.name', function () {
//Do something
}, 5);
Wednesday, May 15, 13
Hooks
$app = new SlimSlim();
$app->hook('the.hook.name', function () {
//Do something
}, 5);
Optional Priority
Wednesday, May 15, 13
Middleware + Hooks = WIN
Wednesday, May 15, 13
Middleware + Hooks
Using middleware to register hooks allows
me to inspect, analyze, or modify my
application at a specific time in the
application’s lifecycle in a DRY, testable, and
reusable manner.
Wednesday, May 15, 13
Authentication Example
Wednesday, May 15, 13
public function call()
{
$app = $this->app;
$req = $app->request();
$auth = $this->auth;
$config = $this->config;
// $checkAuth anonymous function snipped
$this->app->hook('slim.before.router', $checkAuth);
$this->next->call();
}
Wednesday, May 15, 13
public function call()
{
$app = $this->app;
$req = $app->request();
$auth = $this->auth;
$config = $this->config;
// $checkAuth anonymous function snipped
$this->app->hook('slim.before.router', $checkAuth);
$this->next->call();
}
Grab stuff to
inspect
Wednesday, May 15, 13
public function call()
{
$app = $this->app;
$req = $app->request();
$auth = $this->auth;
$config = $this->config;
// $checkAuth anonymous function snipped
$this->app->hook('slim.before.router', $checkAuth);
$this->next->call();
}
Grab stuff to
inspect
(via constructor)
Wednesday, May 15, 13
public function call()
{
$app = $this->app;
$req = $app->request();
$auth = $this->auth;
$config = $this->config;
// $checkAuth anonymous function snipped
$this->app->hook('slim.before.router', $checkAuth);
$this->next->call();
}
Grab stuff to
inspect
Register hook
(via constructor)
Wednesday, May 15, 13
// Snip looping through secured url array
if (preg_match($urlPattern, $req->getPathInfo())
&& !$auth->hasIdentity()) {
if ($req->getPath() !== $config['login.url']) {
$app->redirect($config['login.url']);
}
}
Wednesday, May 15, 13
// Snip looping through secured url array
if (preg_match($urlPattern, $req->getPathInfo())
&& !$auth->hasIdentity()) {
if ($req->getPath() !== $config['login.url']) {
$app->redirect($config['login.url']);
}
}
Match path to
secured url
Wednesday, May 15, 13
// Snip looping through secured url array
if (preg_match($urlPattern, $req->getPathInfo())
&& !$auth->hasIdentity()) {
if ($req->getPath() !== $config['login.url']) {
$app->redirect($config['login.url']);
}
}
Match path to
secured url
Logged in?
Wednesday, May 15, 13
// Snip looping through secured url array
if (preg_match($urlPattern, $req->getPathInfo())
&& !$auth->hasIdentity()) {
if ($req->getPath() !== $config['login.url']) {
$app->redirect($config['login.url']);
}
}
Match path to
secured url
Logged in?
Redirect
Wednesday, May 15, 13
Views
Wednesday, May 15, 13
SlimView
Wednesday, May 15, 13
SlimView
Slim delegates rendering of templates to its view object.
Wednesday, May 15, 13
SlimView
Slim delegates rendering of templates to its view object.
Easily extensible by extending theView class and
returning a string from render()
Wednesday, May 15, 13
SlimView
Slim delegates rendering of templates to its view object.
Easily extensible by extending theView class and
returning a string from render()
Use Slim application’s render() method in your app
Wednesday, May 15, 13
SlimView
Slim delegates rendering of templates to its view object.
Easily extensible by extending theView class and
returning a string from render()
Use Slim application’s render() method in your app
Will echo() template output, buffer the output, and
append to response object’s body
Wednesday, May 15, 13
Rendering an app view
$app->render(
'hello.html',
array( 'name' => 'Josh' ),
200
);
Wednesday, May 15, 13
Rendering an app view
$app->render(
'hello.html',
array( 'name' => 'Josh' ),
200
);
Template
Wednesday, May 15, 13
Rendering an app view
$app->render(
'hello.html',
array( 'name' => 'Josh' ),
200
);
Template View data
(optional)
Wednesday, May 15, 13
Rendering an app view
$app->render(
'hello.html',
array( 'name' => 'Josh' ),
200
);
Template View data
(optional)
HTTP Response
(optional)
Wednesday, May 15, 13
Templates
Wednesday, May 15, 13
Two great tastes
that taste great together
Wednesday, May 15, 13
Twig
Wednesday, May 15, 13
Twig
Concise
Wednesday, May 15, 13
Twig
Concise
Template oriented
Wednesday, May 15, 13
Twig
Concise
Template oriented
Fast
Wednesday, May 15, 13
Twig
Concise
Template oriented
Fast
Multiple inheritance
Wednesday, May 15, 13
Twig
Concise
Template oriented
Fast
Multiple inheritance
Content blocks
Wednesday, May 15, 13
Twig
Concise
Template oriented
Fast
Multiple inheritance
Content blocks
Automatic escaping
Wednesday, May 15, 13
Bootstrap
Because I majorly suck at design
Wednesday, May 15, 13
Caveat
I chose Twig because I wanted to learn Twig,
but you could choose any or more of the
following:
PHP, Mustache, Haml, Haanga, Blitz,
Dwoo . . .
https://github.com/codeguy/Slim-Extras
Wednesday, May 15, 13
layout.html
and
index.html
Wednesday, May 15, 13
layout.html
and
index.html
Wednesday, May 15, 13
layout.html
and
index.html
Wednesday, May 15, 13
layout.html
Wednesday, May 15, 13
<title>{% block page_title %} {% endblock %}</title>
layout.html: title
Wednesday, May 15, 13
<ul class="nav">
{% for link in navigation %}
<li class="{{link.class}}">
<a href="{{link.href}}">{{link.caption}}</
a>
</li>
{% endfor %}
</ul>
layout.html: navigation
Wednesday, May 15, 13
<h1>365 Days of Photography</h1>
<h3>Photographer: Jeremy Kendall</h3>
{% block content %} {% endblock %}
<hr />
layout.html:
headers and content
Wednesday, May 15, 13
index.html
(extends layout.html)
Wednesday, May 15, 13
{% 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 %}
Wednesday, May 15, 13
{% 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
Wednesday, May 15, 13
{% 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
<title />
Wednesday, May 15, 13
{% 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
<title />
Wednesday, May 15, 13
{% 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
<title />
iterator
Wednesday, May 15, 13
{% 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
<title />
iterator
else
Wednesday, May 15, 13
{% 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
<title />
iterator
else
format
Wednesday, May 15, 13
login.html
Wednesday, May 15, 13
{% 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 %}
login.html
Wednesday, May 15, 13
{% 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 %}
login.html
Wednesday, May 15, 13
The other templates
are just more of the same
Wednesday, May 15, 13
Application Code
Another big hurdle I had with Slim was
figuring out how to organize my application
code.
Wednesday, May 15, 13
Thin Controller, Fat Model
Wednesday, May 15, 13
Thin Controller, Fat Model
Duh!
Wednesday, May 15, 13
Thin Controller, Fat Model
Duh!
All my application code is in a library directory
Wednesday, May 15, 13
Thin Controller, Fat Model
Duh!
All my application code is in a library directory
It’s all namespaced, autoloadable, and testable
Wednesday, May 15, 13
Thin Controller, Fat Model
Duh!
All my application code is in a library directory
It’s all namespaced, autoloadable, and testable
I have (almost) zero business logic in index.php
Wednesday, May 15, 13
Thin Controller, Fat Model
Duh!
All my application code is in a library directory
It’s all namespaced, autoloadable, and testable
I have (almost) zero business logic in index.php
Dependencies are managed by Composer
Wednesday, May 15, 13
Thin Controller, Fat Model
Duh!
All my application code is in a library directory
It’s all namespaced, autoloadable, and testable
I have (almost) zero business logic in index.php
Dependencies are managed by Composer
I could theoretically switch frameworks with very little
effort
Wednesday, May 15, 13
GOTO 0
Wednesday, May 15, 13
Small but powerful GOTO 0
Wednesday, May 15, 13
Small but powerful
Excellent tools to write elegant code
GOTO 0
Wednesday, May 15, 13
Small but powerful
Excellent tools to write elegant code
Routing, middleware, hooks, templates, and
views
GOTO 0
Wednesday, May 15, 13
Small but powerful
Excellent tools to write elegant code
Routing, middleware, hooks, templates, and
views
I just scratched the surface
GOTO 0
Wednesday, May 15, 13
Read
Slim: slimframework.com
Twig: twig.sensiolabs.org
Composer: getcomposer.org
MicroPHP Manifesto: microphp.org
Flaming Archer: http://git.io/rH0nrg
Wednesday, May 15, 13
Questions?
Wednesday, May 15, 13
Thanks!
jeremy@jeremykendall.net
@jeremykendall
http://joind.in/8175
Wednesday, May 15, 13

Contenu connexe

Tendances

Artificial Intelligence Drone
Artificial Intelligence DroneArtificial Intelligence Drone
Artificial Intelligence DroneBasilA2
 
Web scraping
Web scrapingWeb scraping
Web scrapingSelecto
 
PDT DC015 Chapter 1 Introduction to IT 2017/18
PDT DC015 Chapter 1 Introduction to IT 2017/18PDT DC015 Chapter 1 Introduction to IT 2017/18
PDT DC015 Chapter 1 Introduction to IT 2017/18Fizaril Amzari Omar
 
Smartphone and its features
Smartphone and its features Smartphone and its features
Smartphone and its features Liton Ahmed
 
Indian air force
Indian air forceIndian air force
Indian air forceARHAMJAIN48
 
Advanced Web Development in PHP - Understanding REST API
Advanced Web Development in PHP - Understanding REST APIAdvanced Web Development in PHP - Understanding REST API
Advanced Web Development in PHP - Understanding REST APIRasan Samarasinghe
 
Android Operating System
Android Operating SystemAndroid Operating System
Android Operating SystemBilal Mirza
 
Ppt on World Of Smartphones
Ppt on World Of SmartphonesPpt on World Of Smartphones
Ppt on World Of SmartphonesPulkit Syal
 
Mobile Application Design & Development
Mobile Application Design & DevelopmentMobile Application Design & Development
Mobile Application Design & DevelopmentRonnie Liew
 
UNMANNED AERIAL VEHICLES
UNMANNED AERIAL VEHICLESUNMANNED AERIAL VEHICLES
UNMANNED AERIAL VEHICLESooseravelli
 
Android Operating System
Android Operating SystemAndroid Operating System
Android Operating Systemrenoy reji
 
Introduction to Android and Android Studio
Introduction to Android and Android StudioIntroduction to Android and Android Studio
Introduction to Android and Android StudioSuyash Srijan
 

Tendances (20)

Artificial Intelligence Drone
Artificial Intelligence DroneArtificial Intelligence Drone
Artificial Intelligence Drone
 
Fitness App ppt
Fitness App pptFitness App ppt
Fitness App ppt
 
internet world, computer ppt
internet world, computer pptinternet world, computer ppt
internet world, computer ppt
 
Web scraping
Web scrapingWeb scraping
Web scraping
 
PDT DC015 Chapter 1 Introduction to IT 2017/18
PDT DC015 Chapter 1 Introduction to IT 2017/18PDT DC015 Chapter 1 Introduction to IT 2017/18
PDT DC015 Chapter 1 Introduction to IT 2017/18
 
Smartphone and its features
Smartphone and its features Smartphone and its features
Smartphone and its features
 
Indian air force
Indian air forceIndian air force
Indian air force
 
Android vs Ios
Android vs Ios Android vs Ios
Android vs Ios
 
Ethiopian coffee
Ethiopian coffee Ethiopian coffee
Ethiopian coffee
 
Indian Air Force
Indian Air ForceIndian Air Force
Indian Air Force
 
Advanced Web Development in PHP - Understanding REST API
Advanced Web Development in PHP - Understanding REST APIAdvanced Web Development in PHP - Understanding REST API
Advanced Web Development in PHP - Understanding REST API
 
Evolution of Android
Evolution of AndroidEvolution of Android
Evolution of Android
 
Yelp | UX
Yelp | UX Yelp | UX
Yelp | UX
 
Android Operating System
Android Operating SystemAndroid Operating System
Android Operating System
 
Ppt on World Of Smartphones
Ppt on World Of SmartphonesPpt on World Of Smartphones
Ppt on World Of Smartphones
 
Android ppt
Android ppt Android ppt
Android ppt
 
Mobile Application Design & Development
Mobile Application Design & DevelopmentMobile Application Design & Development
Mobile Application Design & Development
 
UNMANNED AERIAL VEHICLES
UNMANNED AERIAL VEHICLESUNMANNED AERIAL VEHICLES
UNMANNED AERIAL VEHICLES
 
Android Operating System
Android Operating SystemAndroid Operating System
Android Operating System
 
Introduction to Android and Android Studio
Introduction to Android and Android StudioIntroduction to Android and Android Studio
Introduction to Android and Android Studio
 

Similaire à Keeping it small - Getting to know the Slim PHP micro framework

Tek 2013 - Building Web Apps from a New Angle with AngularJS
Tek 2013 - Building Web Apps from a New Angle with AngularJSTek 2013 - Building Web Apps from a New Angle with AngularJS
Tek 2013 - Building Web Apps from a New Angle with AngularJSPablo Godel
 
Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!cloudbring
 
Open Source Monitoring for Java with JMX and Graphite (GeeCON 2013)
Open Source Monitoring for Java with JMX and Graphite (GeeCON 2013)Open Source Monitoring for Java with JMX and Graphite (GeeCON 2013)
Open Source Monitoring for Java with JMX and Graphite (GeeCON 2013)Cyrille Le Clerc
 
Quality Use Of Plugin
Quality Use Of PluginQuality Use Of Plugin
Quality Use Of PluginYasuo Harada
 
What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...Richard McIntyre
 
OSDC 2014: Ole Michaelis & Sönke Rümpler: Make it SOLID - Software Architectu...
OSDC 2014: Ole Michaelis & Sönke Rümpler: Make it SOLID - Software Architectu...OSDC 2014: Ole Michaelis & Sönke Rümpler: Make it SOLID - Software Architectu...
OSDC 2014: Ole Michaelis & Sönke Rümpler: Make it SOLID - Software Architectu...NETWAYS
 
High Performance WordPress
High Performance WordPressHigh Performance WordPress
High Performance WordPressvnsavage
 
Building a Startup Stack with AngularJS
Building a Startup Stack with AngularJSBuilding a Startup Stack with AngularJS
Building a Startup Stack with AngularJSFITC
 
Application Logging With The ELK Stack
Application Logging With The ELK StackApplication Logging With The ELK Stack
Application Logging With The ELK Stackbenwaine
 
Functional Reactive Programming in the Netflix API
Functional Reactive Programming in the Netflix APIFunctional Reactive Programming in the Netflix API
Functional Reactive Programming in the Netflix APIC4Media
 
Advanced App Building - Tips, Tricks & Lessons Learned
Advanced App Building - Tips, Tricks & Lessons LearnedAdvanced App Building - Tips, Tricks & Lessons Learned
Advanced App Building - Tips, Tricks & Lessons LearnedJay Graves
 
Fast Slim Correct: The History and Evolution of JavaScript.
Fast Slim Correct: The History and Evolution of JavaScript.Fast Slim Correct: The History and Evolution of JavaScript.
Fast Slim Correct: The History and Evolution of JavaScript.John Dalziel
 
Drupal 8 configuration system for coders and site builders - Drupalaton 2013
Drupal 8 configuration system for coders and site builders - Drupalaton 2013Drupal 8 configuration system for coders and site builders - Drupalaton 2013
Drupal 8 configuration system for coders and site builders - Drupalaton 2013swentel
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90minsLarry Cai
 

Similaire à Keeping it small - Getting to know the Slim PHP micro framework (20)

Tek 2013 - Building Web Apps from a New Angle with AngularJS
Tek 2013 - Building Web Apps from a New Angle with AngularJSTek 2013 - Building Web Apps from a New Angle with AngularJS
Tek 2013 - Building Web Apps from a New Angle with AngularJS
 
Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!Rapid Prototyping FTW!!!
Rapid Prototyping FTW!!!
 
Open Source Monitoring for Java with JMX and Graphite (GeeCON 2013)
Open Source Monitoring for Java with JMX and Graphite (GeeCON 2013)Open Source Monitoring for Java with JMX and Graphite (GeeCON 2013)
Open Source Monitoring for Java with JMX and Graphite (GeeCON 2013)
 
Quality Use Of Plugin
Quality Use Of PluginQuality Use Of Plugin
Quality Use Of Plugin
 
A false digital alibi on mac os x
A false digital alibi on mac os xA false digital alibi on mac os x
A false digital alibi on mac os x
 
What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...
 
OSDC 2014: Ole Michaelis & Sönke Rümpler: Make it SOLID - Software Architectu...
OSDC 2014: Ole Michaelis & Sönke Rümpler: Make it SOLID - Software Architectu...OSDC 2014: Ole Michaelis & Sönke Rümpler: Make it SOLID - Software Architectu...
OSDC 2014: Ole Michaelis & Sönke Rümpler: Make it SOLID - Software Architectu...
 
High Performance WordPress
High Performance WordPressHigh Performance WordPress
High Performance WordPress
 
Building a Startup Stack with AngularJS
Building a Startup Stack with AngularJSBuilding a Startup Stack with AngularJS
Building a Startup Stack with AngularJS
 
ZF3 introduction
ZF3 introductionZF3 introduction
ZF3 introduction
 
Application Logging With The ELK Stack
Application Logging With The ELK StackApplication Logging With The ELK Stack
Application Logging With The ELK Stack
 
Functional Reactive Programming in the Netflix API
Functional Reactive Programming in the Netflix APIFunctional Reactive Programming in the Netflix API
Functional Reactive Programming in the Netflix API
 
Mojolicious lite
Mojolicious liteMojolicious lite
Mojolicious lite
 
Advanced App Building - Tips, Tricks & Lessons Learned
Advanced App Building - Tips, Tricks & Lessons LearnedAdvanced App Building - Tips, Tricks & Lessons Learned
Advanced App Building - Tips, Tricks & Lessons Learned
 
Empezando con Twig
Empezando con TwigEmpezando con Twig
Empezando con Twig
 
Fast Slim Correct: The History and Evolution of JavaScript.
Fast Slim Correct: The History and Evolution of JavaScript.Fast Slim Correct: The History and Evolution of JavaScript.
Fast Slim Correct: The History and Evolution of JavaScript.
 
Drupal 8 configuration system for coders and site builders - Drupalaton 2013
Drupal 8 configuration system for coders and site builders - Drupalaton 2013Drupal 8 configuration system for coders and site builders - Drupalaton 2013
Drupal 8 configuration system for coders and site builders - Drupalaton 2013
 
Demystifying Maven
Demystifying MavenDemystifying Maven
Demystifying Maven
 
Introduce Django
Introduce DjangoIntroduce Django
Introduce Django
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90mins
 

Plus de 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
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkJeremy Kendall
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkJeremy 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
 

Plus de Jeremy Kendall (16)

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
 
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro FrameworkKeeping it Small: Getting to know the Slim Micro Framework
Keeping it Small: Getting to know the Slim Micro Framework
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
 
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
 

Dernier

Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 

Dernier (20)

Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 

Keeping it small - Getting to know the Slim PHP micro framework

  • 1. Keeping it small Getting to know the Slim micro framework php[tek] 2013 Wednesday, May 15, 13
  • 3. I love to code Wednesday, May 15, 13
  • 4. I love to code I’m terribly forgetful Wednesday, May 15, 13
  • 5. I love to code I’m terribly forgetful I take pictures Wednesday, May 15, 13
  • 6. I love to code I’m terribly forgetful I take pictures I work at OpenSky Wednesday, May 15, 13
  • 9. MicroPHP Manifesto Written by Ed Finkler Wednesday, May 15, 13
  • 10. MicroPHP Manifesto Written by Ed Finkler Punk rock vs. Prog rock Wednesday, May 15, 13
  • 11. MicroPHP Manifesto Written by Ed Finkler Punk rock vs. Prog rock Prophet or Madman? Wednesday, May 15, 13
  • 12. MicroPHP Manifesto Written by Ed Finkler Punk rock vs. Prog rock Prophet or Madman? Guiding principle Wednesday, May 15, 13
  • 13. MicroPHP Manifesto Written by Ed Finkler Punk rock vs. Prog rock Prophet or Madman? Guiding principle http://microphp.org/ Wednesday, May 15, 13
  • 16. Micro framework? Concise codebase Clear codebase Wednesday, May 15, 13
  • 17. Micro framework? Concise codebase Clear codebase Addresses a small set of use cases Wednesday, May 15, 13
  • 18. Micro framework? Concise codebase Clear codebase Addresses a small set of use cases Addresses those use cases well Wednesday, May 15, 13
  • 19. I chose Slim PHP Wednesday, May 15, 13
  • 20. I chose Slim PHP and I sucked at it Wednesday, May 15, 13
  • 22. What is Slim? Inspired by Sinatra Wednesday, May 15, 13
  • 23. What is Slim? Inspired by Sinatra Favors cleanliness over terseness Wednesday, May 15, 13
  • 24. What is Slim? Inspired by Sinatra Favors cleanliness over terseness Favors common cases over edge cases Wednesday, May 15, 13
  • 26. Install Composer curl -s https://getcomposer.org/installer | php Wednesday, May 15, 13
  • 27. Install Composer curl -s https://getcomposer.org/installer | php If you take nothing else away from this talk, I hope that it’s Composer. It’s that big of a deal. Wednesday, May 15, 13
  • 29. Install via Composer php composer.phar install Wednesday, May 15, 13
  • 30. Add this to index.php <?php require 'vendor/autoload.php'; Wednesday, May 15, 13
  • 31. Pro tip mv composer.phar /usr/local/bin/composer Wednesday, May 15, 13
  • 32. Don’t forget .htaccess! RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [QSA,L] http://docs.slimframework.com/#Route-URL-Rewriting (nginx documentation available at same URL) Wednesday, May 15, 13
  • 33. Hello $name <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run(); Wednesday, May 15, 13
  • 34. Hello $name <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run(); Wednesday, May 15, 13
  • 35. Hello $name <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run(); Wednesday, May 15, 13
  • 36. Hello $name <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run(); Wednesday, May 15, 13
  • 37. Hello $name <?php require '../vendor/autoload.php'; $app = new SlimSlim(); $app->get('/hello/:name', function ($name) { echo "Hello, $name"; }); $app->run(); Wednesday, May 15, 13
  • 41. “Great repository names are short and memorable. Need inspiration? How about flaming-archer.” Wednesday, May 15, 13
  • 43. Flaming Archer Photo 365 project Wednesday, May 15, 13
  • 44. Flaming Archer Photo 365 project Bulk of app built in 4 days Wednesday, May 15, 13
  • 45. Flaming Archer Photo 365 project Bulk of app built in 4 days Basic application — a few bells, no whistles Wednesday, May 15, 13
  • 46. Flaming Archer Photo 365 project Bulk of app built in 4 days Basic application — a few bells, no whistles Routing Wednesday, May 15, 13
  • 47. Flaming Archer Photo 365 project Bulk of app built in 4 days Basic application — a few bells, no whistles Routing Twig templates Wednesday, May 15, 13
  • 48. Flaming Archer Photo 365 project Bulk of app built in 4 days Basic application — a few bells, no whistles Routing Twig templates Middleware Wednesday, May 15, 13
  • 49. Flaming Archer Photo 365 project Bulk of app built in 4 days Basic application — a few bells, no whistles Routing Twig templates Middleware Hooks Wednesday, May 15, 13
  • 55. phploc --exclude vendor --exclude tests --exclude templates . phploc 1.7.4 by Sebastian Bergmann. Directories: 8 Files: 16 Lines of Code (LOC): 1212 Cyclomatic Complexity / Lines of Code: 0.03 Comment Lines of Code (CLOC): 453 Non-Comment Lines of Code (NCLOC): 759 Wednesday, May 15, 13
  • 57. 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( // . . . ) ); Wednesday, May 15, 13
  • 58. 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( // . . . ) ); Slim Wednesday, May 15, 13
  • 59. 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( // . . . ) ); Slim Views Wednesday, May 15, 13
  • 60. 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( // . . . ) ); Slim Views Cookies Wednesday, May 15, 13
  • 61. 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( // . . . ) ); Slim Views Cookies App specific Wednesday, May 15, 13
  • 62. $config = require_once __DIR__ . '/../config.php'; // Prepare app $app = new SlimSlim($config['slim']); Configuration Wednesday, May 15, 13
  • 63. $config = require_once __DIR__ . '/../config.php'; // Prepare app $app = new SlimSlim($config['slim']); Config array goes here Configuration Wednesday, May 15, 13
  • 65. Routing $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } ); Wednesday, May 15, 13
  • 66. Routing $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } ); HTTP Method Wednesday, May 15, 13
  • 67. Routing $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } ); HTTP Method Resource URI Wednesday, May 15, 13
  • 68. Routing $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } ); HTTP Method Resource URI Anonymous Function Wednesday, May 15, 13
  • 69. Routing $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } ); Wednesday, May 15, 13
  • 70. Routing $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } ); Grabs all the pics Wednesday, May 15, 13
  • 71. Routing $app->get('/', function () use ($app, $service) { $images = $service->findAll(); $app->render('index.html', array('images' => $images)); } ); Grabs all the pics Passes array of image data to index.html Wednesday, May 15, 13
  • 72. 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])')); Wednesday, May 15, 13
  • 73. 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])')); URL parameter Wednesday, May 15, 13
  • 74. 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])')); URL parameter ... gets passed as an argument Wednesday, May 15, 13
  • 75. 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])')); URL parameter ... gets passed as an argument Condition Wednesday, May 15, 13
  • 76. 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])')); URL parameter ... gets passed as an argument Condition 1 to 366 Wednesday, May 15, 13
  • 77. 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])')); 404! Wednesday, May 15, 13
  • 78. POST (with redirect) $app->post('/admin/add-photo', function() use ($app, $service) { $data = $app->request()->post(); $service->save($data); $app->redirect('/admin'); } ); Wednesday, May 15, 13
  • 79. 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 Wednesday, May 15, 13
  • 80. 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 Wednesday, May 15, 13
  • 81. Multiple methods $app->map('/login', function() { // Login } )->via('GET', 'POST'); Wednesday, May 15, 13
  • 82. Multiple methods $app->map('/login', function() { // Login } )->via('GET', 'POST'); Not an HTTP Method Wednesday, May 15, 13
  • 83. Multiple methods $app->map('/login', function() { // Login } )->via('GET', 'POST'); Not an HTTP Method via() is the awesome sauce Wednesday, May 15, 13
  • 84. Logging and flash messaging Wednesday, May 15, 13
  • 85. $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'); } ); Wednesday, May 15, 13
  • 86. $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'); } ); Get the log from $app Wednesday, May 15, 13
  • 87. $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'); } ); Get the log from $app Error! Wednesday, May 15, 13
  • 88. $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'); } ); Get the log from $app Error! Flash message available in the next request. Wednesday, May 15, 13
  • 89. Middleware “. . . a Slim application can have middleware that may inspect, analyze, or modify the application environment, request, and response before and/or after the Slim application is invoked.” http://docs.slimframework.com/#Middleware-Overview Wednesday, May 15, 13
  • 91. Middleware Like layers of an onion Wednesday, May 15, 13
  • 92. Middleware Like layers of an onion The Slim application is the core of the onion Wednesday, May 15, 13
  • 93. Middleware Like layers of an onion The Slim application is the core of the onion Each new middleware wraps any existing middleware Wednesday, May 15, 13
  • 94. Middleware Like layers of an onion The Slim application is the core of the onion Each new middleware wraps any existing middleware Each middleware optionally calls the next middleware in the chain Wednesday, May 15, 13
  • 95. Middleware Like layers of an onion The Slim application is the core of the onion Each new middleware wraps any existing middleware Each middleware optionally calls the next middleware in the chain Middleware is executed from the outside in Wednesday, May 15, 13
  • 96. Middleware Like layers of an onion The Slim application is the core of the onion Each new middleware wraps any existing middleware Each middleware optionally calls the next middleware in the chain Middleware is executed from the outside in Pay careful attention to the order in which you register middleware Wednesday, May 15, 13
  • 97. Middleware // Prepare app $app = new SlimSlim($config['slim']); // . . . $app->add(new Navigation($auth)); $app->add(new Authentication($auth, $config)); Wednesday, May 15, 13
  • 98. Middleware // Prepare app $app = new SlimSlim($config['slim']); // . . . $app->add(new Navigation($auth)); $app->add(new Authentication($auth, $config)); Wednesday, May 15, 13
  • 99. Middleware // Prepare app $app = new SlimSlim($config['slim']); // . . . $app->add(new Navigation($auth)); $app->add(new Authentication($auth, $config)); Wednesday, May 15, 13
  • 102. Existing Middleware Flash messaging Content types Wednesday, May 15, 13
  • 103. Existing Middleware Flash messaging Content types Pretty exceptions Wednesday, May 15, 13
  • 104. Existing Middleware Flash messaging Content types Pretty exceptions Session cookie Wednesday, May 15, 13
  • 105. Existing Middleware Flash messaging Content types Pretty exceptions Session cookie More in Slim Extras Wednesday, May 15, 13
  • 106. Roll your own Middleware Wednesday, May 15, 13
  • 107. Roll your own Middleware Super easy Wednesday, May 15, 13
  • 108. Roll your own Middleware Super easy DRYs up code Wednesday, May 15, 13
  • 109. Roll your own Middleware Super easy DRYs up code Awesome application wide functionality Wednesday, May 15, 13
  • 110. Roll your own Middleware Super easy DRYs up code Awesome application wide functionality Just extend SlimMiddleware and implement call() Wednesday, May 15, 13
  • 111. 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(); } } Wednesday, May 15, 13
  • 112. 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(); } } Extend this Wednesday, May 15, 13
  • 113. 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(); } } Extend this Define call() Wednesday, May 15, 13
  • 114. 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(); } } Extend this Define call() Inspect, analyze, and modify! Wednesday, May 15, 13
  • 115. 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(); } } Extend this Define call() On to the next! Inspect, analyze, and modify! Wednesday, May 15, 13
  • 117. namespace FaMiddleware; use ZendAuthenticationAuthenticationService; class Navigation extends SlimMiddleware { /** @var AuthenticationService */ private $auth; public function __construct(AuthenticationService $auth) { $this->auth = $auth; } public function call() { // . . . } } Wednesday, May 15, 13
  • 118. namespace FaMiddleware; use ZendAuthenticationAuthenticationService; class Navigation extends SlimMiddleware { /** @var AuthenticationService */ private $auth; public function __construct(AuthenticationService $auth) { $this->auth = $auth; } public function call() { // . . . } } extends Wednesday, May 15, 13
  • 119. namespace FaMiddleware; use ZendAuthenticationAuthenticationService; class Navigation extends SlimMiddleware { /** @var AuthenticationService */ private $auth; public function __construct(AuthenticationService $auth) { $this->auth = $auth; } public function call() { // . . . } } Constructor injection FTW extends Wednesday, May 15, 13
  • 120. 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); } // . . . } Wednesday, May 15, 13
  • 121. 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); } // . . . } Arrays of nav items Wednesday, May 15, 13
  • 122. 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); } // . . . } Arrays of nav items Nav differs based on auth status Wednesday, May 15, 13
  • 123. public function call() { // . . . foreach ($navigation as &$link) { if ($link['href'] == $req->getPath()) { $link['class'] = 'active'; } else { $link['class'] = ''; } } $app->view()->appendData(array('navigation' => $navigation)); $this->next->call(); } Wednesday, May 15, 13
  • 124. public function call() { // . . . foreach ($navigation as &$link) { if ($link['href'] == $req->getPath()) { $link['class'] = 'active'; } else { $link['class'] = ''; } } $app->view()->appendData(array('navigation' => $navigation)); $this->next->call(); } Match dispatched path Wednesday, May 15, 13
  • 125. public function call() { // . . . foreach ($navigation as &$link) { if ($link['href'] == $req->getPath()) { $link['class'] = 'active'; } else { $link['class'] = ''; } } $app->view()->appendData(array('navigation' => $navigation)); $this->next->call(); } Match dispatched path Append $navigation to view Wednesday, May 15, 13
  • 126. public function call() { // . . . foreach ($navigation as &$link) { if ($link['href'] == $req->getPath()) { $link['class'] = 'active'; } else { $link['class'] = ''; } } $app->view()->appendData(array('navigation' => $navigation)); $this->next->call(); } Match dispatched path Append $navigation to view On to the next! Wednesday, May 15, 13
  • 128. Route Middleware Anything that returns true for is_callable() Wednesday, May 15, 13
  • 129. Route Middleware Anything that returns true for is_callable() Apply directly to route! Wednesday, May 15, 13
  • 130. Route Middleware Anything that returns true for is_callable() Apply directly to route! Goes between route definition and route callable Wednesday, May 15, 13
  • 131. Route Middleware <?php function mw1() { echo "This is middleware!"; } function mw2() { echo "This is middleware!"; } $app = new SlimSlim(); $app->get('/foo', 'mw1', 'mw2', function () { //Do something }); http://docs.slimframework.com/#Route-Middleware Wednesday, May 15, 13
  • 132. Route Middleware <?php function mw1() { echo "This is middleware!"; } function mw2() { echo "This is middleware!"; } $app = new SlimSlim(); $app->get('/foo', 'mw1', 'mw2', function () { //Do something }); http://docs.slimframework.com/#Route-Middleware Wednesday, May 15, 13
  • 133. Hooks A “hook” is a moment in the Slim application lifecycle at which a priority list of callables assigned to the hook will be invoked.A hook is identified by a string name. http://docs.slimframework.com/#Hooks-Overview Wednesday, May 15, 13
  • 135. Hooks Anything that returns true for is_callable() Wednesday, May 15, 13
  • 136. Hooks Anything that returns true for is_callable() Prioritized Wednesday, May 15, 13
  • 137. Hooks Anything that returns true for is_callable() Prioritized Six default hooks Wednesday, May 15, 13
  • 146. Hooks $app = new SlimSlim(); $app->hook('the.hook.name', function () { //Do something }, 5); Wednesday, May 15, 13
  • 147. Hooks $app = new SlimSlim(); $app->hook('the.hook.name', function () { //Do something }, 5); Optional Priority Wednesday, May 15, 13
  • 148. Middleware + Hooks = WIN Wednesday, May 15, 13
  • 149. Middleware + Hooks Using middleware to register hooks allows me to inspect, analyze, or modify my application at a specific time in the application’s lifecycle in a DRY, testable, and reusable manner. Wednesday, May 15, 13
  • 151. public function call() { $app = $this->app; $req = $app->request(); $auth = $this->auth; $config = $this->config; // $checkAuth anonymous function snipped $this->app->hook('slim.before.router', $checkAuth); $this->next->call(); } Wednesday, May 15, 13
  • 152. public function call() { $app = $this->app; $req = $app->request(); $auth = $this->auth; $config = $this->config; // $checkAuth anonymous function snipped $this->app->hook('slim.before.router', $checkAuth); $this->next->call(); } Grab stuff to inspect Wednesday, May 15, 13
  • 153. public function call() { $app = $this->app; $req = $app->request(); $auth = $this->auth; $config = $this->config; // $checkAuth anonymous function snipped $this->app->hook('slim.before.router', $checkAuth); $this->next->call(); } Grab stuff to inspect (via constructor) Wednesday, May 15, 13
  • 154. public function call() { $app = $this->app; $req = $app->request(); $auth = $this->auth; $config = $this->config; // $checkAuth anonymous function snipped $this->app->hook('slim.before.router', $checkAuth); $this->next->call(); } Grab stuff to inspect Register hook (via constructor) Wednesday, May 15, 13
  • 155. // Snip looping through secured url array if (preg_match($urlPattern, $req->getPathInfo()) && !$auth->hasIdentity()) { if ($req->getPath() !== $config['login.url']) { $app->redirect($config['login.url']); } } Wednesday, May 15, 13
  • 156. // Snip looping through secured url array if (preg_match($urlPattern, $req->getPathInfo()) && !$auth->hasIdentity()) { if ($req->getPath() !== $config['login.url']) { $app->redirect($config['login.url']); } } Match path to secured url Wednesday, May 15, 13
  • 157. // Snip looping through secured url array if (preg_match($urlPattern, $req->getPathInfo()) && !$auth->hasIdentity()) { if ($req->getPath() !== $config['login.url']) { $app->redirect($config['login.url']); } } Match path to secured url Logged in? Wednesday, May 15, 13
  • 158. // Snip looping through secured url array if (preg_match($urlPattern, $req->getPathInfo()) && !$auth->hasIdentity()) { if ($req->getPath() !== $config['login.url']) { $app->redirect($config['login.url']); } } Match path to secured url Logged in? Redirect Wednesday, May 15, 13
  • 161. SlimView Slim delegates rendering of templates to its view object. Wednesday, May 15, 13
  • 162. SlimView Slim delegates rendering of templates to its view object. Easily extensible by extending theView class and returning a string from render() Wednesday, May 15, 13
  • 163. SlimView Slim delegates rendering of templates to its view object. Easily extensible by extending theView class and returning a string from render() Use Slim application’s render() method in your app Wednesday, May 15, 13
  • 164. SlimView Slim delegates rendering of templates to its view object. Easily extensible by extending theView class and returning a string from render() Use Slim application’s render() method in your app Will echo() template output, buffer the output, and append to response object’s body Wednesday, May 15, 13
  • 165. Rendering an app view $app->render( 'hello.html', array( 'name' => 'Josh' ), 200 ); Wednesday, May 15, 13
  • 166. Rendering an app view $app->render( 'hello.html', array( 'name' => 'Josh' ), 200 ); Template Wednesday, May 15, 13
  • 167. Rendering an app view $app->render( 'hello.html', array( 'name' => 'Josh' ), 200 ); Template View data (optional) Wednesday, May 15, 13
  • 168. Rendering an app view $app->render( 'hello.html', array( 'name' => 'Josh' ), 200 ); Template View data (optional) HTTP Response (optional) Wednesday, May 15, 13
  • 170. Two great tastes that taste great together Wednesday, May 15, 13
  • 177. Twig Concise Template oriented Fast Multiple inheritance Content blocks Automatic escaping Wednesday, May 15, 13
  • 178. Bootstrap Because I majorly suck at design Wednesday, May 15, 13
  • 179. Caveat I chose Twig because I wanted to learn Twig, but you could choose any or more of the following: PHP, Mustache, Haml, Haanga, Blitz, Dwoo . . . https://github.com/codeguy/Slim-Extras Wednesday, May 15, 13
  • 184. <title>{% block page_title %} {% endblock %}</title> layout.html: title Wednesday, May 15, 13
  • 185. <ul class="nav"> {% for link in navigation %} <li class="{{link.class}}"> <a href="{{link.href}}">{{link.caption}}</ a> </li> {% endfor %} </ul> layout.html: navigation Wednesday, May 15, 13
  • 186. <h1>365 Days of Photography</h1> <h3>Photographer: Jeremy Kendall</h3> {% block content %} {% endblock %} <hr /> layout.html: headers and content Wednesday, May 15, 13
  • 188. {% 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 %} Wednesday, May 15, 13
  • 189. {% 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 Wednesday, May 15, 13
  • 190. {% 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 <title /> Wednesday, May 15, 13
  • 191. {% 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 <title /> Wednesday, May 15, 13
  • 192. {% 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 <title /> iterator Wednesday, May 15, 13
  • 193. {% 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 <title /> iterator else Wednesday, May 15, 13
  • 194. {% 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 <title /> iterator else format Wednesday, May 15, 13
  • 196. {% 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 %} login.html Wednesday, May 15, 13
  • 197. {% 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 %} login.html Wednesday, May 15, 13
  • 198. The other templates are just more of the same Wednesday, May 15, 13
  • 199. Application Code Another big hurdle I had with Slim was figuring out how to organize my application code. Wednesday, May 15, 13
  • 200. Thin Controller, Fat Model Wednesday, May 15, 13
  • 201. Thin Controller, Fat Model Duh! Wednesday, May 15, 13
  • 202. Thin Controller, Fat Model Duh! All my application code is in a library directory Wednesday, May 15, 13
  • 203. Thin Controller, Fat Model Duh! All my application code is in a library directory It’s all namespaced, autoloadable, and testable Wednesday, May 15, 13
  • 204. Thin Controller, Fat Model Duh! All my application code is in a library directory It’s all namespaced, autoloadable, and testable I have (almost) zero business logic in index.php Wednesday, May 15, 13
  • 205. Thin Controller, Fat Model Duh! All my application code is in a library directory It’s all namespaced, autoloadable, and testable I have (almost) zero business logic in index.php Dependencies are managed by Composer Wednesday, May 15, 13
  • 206. Thin Controller, Fat Model Duh! All my application code is in a library directory It’s all namespaced, autoloadable, and testable I have (almost) zero business logic in index.php Dependencies are managed by Composer I could theoretically switch frameworks with very little effort Wednesday, May 15, 13
  • 208. Small but powerful GOTO 0 Wednesday, May 15, 13
  • 209. Small but powerful Excellent tools to write elegant code GOTO 0 Wednesday, May 15, 13
  • 210. Small but powerful Excellent tools to write elegant code Routing, middleware, hooks, templates, and views GOTO 0 Wednesday, May 15, 13
  • 211. Small but powerful Excellent tools to write elegant code Routing, middleware, hooks, templates, and views I just scratched the surface GOTO 0 Wednesday, May 15, 13
  • 212. Read Slim: slimframework.com Twig: twig.sensiolabs.org Composer: getcomposer.org MicroPHP Manifesto: microphp.org Flaming Archer: http://git.io/rH0nrg Wednesday, May 15, 13