Slim 3
The Good, the Bad and the Beta
Ian Littman (@iansltx)
http://ian.im/slim3july15
echo about($me);
- I write and maintain web apps
- Mainly APIs
- Aura, Phalcon, Slim
- Currencly freelancing (and very busy)
- I've written a couple libraries
- BusinessDays
- gcm-client
- https://packagist.org/packages/iansltx/
- I use Slim 3 in prod right now
- I host Austin Web Developer Lunch (see Meetup)
What we'll talk about
- Why Slim?
- How Slim 3 works
- Middleware + PSR-7
- Routing (FastRoute)
- Dependency Injection + Container Interop
- Slim 3 in the real world
- A new microservice
- An upgrade of Raphple (rendered views, Slim 2)
Why Slim? (vs. Silex, Lumen)
- Thin and light - 2727 logical lines of code for slim/slim
- Few dependencies
- FastRoute
- Pimple DI (can be replaced)
- PSR-7 Message Interface
- Continer-Interop Interface
- Standards based
- Mix and match libraries
- Defaults can be overridden (DIC, HTTP message)
- Not highly opinionated
What's it good for?
- Prototyping
- APIs (and microservices!)
- Not being a full-stack framework
Let's get started
<?php require __DIR__ . '/vendor/autoload.php';
$app = new \Slim\App();
$app->get('/', function($req, $res) {
return $res->write('Hello world!');
});
$app->get('/{name}', function($req, $res, $args) {
return $res->write('Hello ' . $args['name'] . '!');
});
$app->run();
Let's get it running
composer init -s dev composer require slim/slim php -S localhost:8080 index.php
How It Works: Middleware
- Sencha Connect + Express
- Ruby Rack (and, yes, Sinatra)
- Layered execution
- Each middleware is a callable with
- Request
- Response
- Callback to next middleware (which may be the app)
- Middleware must return a Response
- Short-circuit return (e.g. caching, failed auth)
- Return (potentially after further modification result of $next($req, $res);
- Each middleware is a callable with
- Immutable objects
- Can be assigned globally, or to a single route
How It Works: Middleware
<?php // $app is instantiated above
$app->add(function($req, $res, $next) { // runs second, right before app
if (!$this->auth->isLoggedIn($req))
return new UnauthedResponse; // assuming it's PSR-7 compliant
return $next($req, $res);
});
$app->add(function($req, $res, $next) { // runs first (outermost)
$startTime = microtime(true);
$res = $next($req->withHeader('Start-Time', $startTime), $res);
return $res->write(
'<!-- Total Time: ' . microtime(true) - $startTime . ' -->');
});
How It Works: Routing
- Super-fast regex-based router
- /users
- /users/{id}
- /users/{id:/d+}
- Routes can cover one or more methods
- $app->get('/my/route', function($req, $res, $args) {...});
- $app->match(['PUT', 'PATCH'], '/not/restful/{id}', $closure);
- Routes can dispatch to closures or call objects from the DI container
- $app->get('/me', 'MyController::someAction');
-
Looks up MyController in the DI container, then calls someAction with the same arguments as a closure would get
-
Route groups (prefixes) are supported
How It Works: DI
$container = new \Slim\Container(); // Pimple + Slim defaults
$container['myService'] = function($c) {
return new MyService($c->get('someOtherDependency');
};
// if you provide the expected services,
// any Container Interop DI container will work here
$app = new \Slim\App($container);
$app->get('/', function($req, $res) { // $this is bound to app
// app proxies __get() to container
return $res->write($this->myService->doACoolThing($req);
});
No longer in Slim 3
- View rendering (use Twig if you want)
- Encryption
- Response cookie handling (coming back soon, maybe...)
- Session/flash support (Composer packages are available)
- Echoing out...just kidding, you can still echo out from route closures
Case Study #1: Microservice
- Purpose: render PDFs from templates using pdflib ext
- Internal API, no auth, HAL formatting
- Multiple clients
- Heartbeat endpoint with failover
- Streamed request logs, custom errors
- LOC: ~300
- Brand new, using Slim 3 from ~3 months ago
Case Study #1: Microservice
- The Good
- Fast
- Relatively quick to dev on, despite lack of docs
- Overriding $app['errorHandler'] is useful
- Returns a function that returns a function...
- ...that takes $req, $res, $exception as params...
- ...and returns a response
- The Bad
- See "The Beta"
- The Beta
- Lack of docs (moving target due to pre-alpha)
- No multipart/form-data support at the time
- Uploaded files support still missing
- Workaround: add DI proxies to $_POST, $_FILES
Case Study #2: Raphple
- Purpose: raffle stuff off using SMS via Twilio
- Rendered views
- ~5 hours of effort
- Built in Slim 2 with a lot of closure use's
- Non-template LOC before/after: ~200/~280
- More classes, no more pulling from global scope
- Added quick 'n' dirty view rendering
- Added quick 'n' dirty cookie setting
- ~1.5 hours, including testing, today
- 2790c230a6cf83367d92f3c2d1036c16e695ed71
Case Study #2: Raphple
- The Good
- Method-chaining on responses is cleaner than v2
- Logic changes were minimal
- Request-related changes were straightforward
- Framework includes less stuff that isn't used
- The Bad
- An easy way to set response cookies was removed
- High % of route LOC changed due to no render() and switch in request format (but I knew that going in)
- The Beta
- Docs are sparse and not up to date (e.g. cookies)
Should I use Slim?
-
When?
-
Now: maybe
-
When released: better idea
-
-
How?
-
APIs: good call
-
Microservices: yep
-
If expecting an opinionated framework: maybe not
-
If you're opinionated: you'll probably like it
-
More Resources
- Rob Allen / @akrabat on YouTube
- Josh Lockhart / @codeguy on NomadPHP ($$$)
- Some more @akrabat articles
- Docs (repo)
- Home page (repo)
- Packagist / GitHub (org)
Q&A
Slim 3: The Good, the Bad and the Beta
By Ian Littman
Slim 3: The Good, the Bad and the Beta
- 4,586