The document discusses the Slim micro PHP framework. It provides an overview of installing Slim via Composer, basic routing examples including GET and POST requests, and configuration options. Key topics covered include routing, templates, middleware, configuration via a config array, and logging/flash messaging. Examples demonstrate basic routing for homepage, single images, adding photos, and handling POST data and redirects.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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