Working with a Database
Unlike Laravel, which bundles the Eloquent ORM, Slim doesn't include any database layer out of the box. That's intentional — Slim leaves the choice up to you. The simplest option is the one you already know from Core PHP: plain PDO (see PHP & MySQL if you need a refresher on connecting and running prepared statements).
Registering PDO in the DI Container
Creating a fresh PDO connection inside every route handler works, but it means you're
opening a new database connection on every single request that needs one, and repeating the same
connection code everywhere. Instead, register it once as a service in the container (see
Dependency Injection) so every route can ask for the
same connection:
<?php
require __DIR__ . '/../vendor/autoload.php';
use DI\Container;
use Slim\Factory\AppFactory;
$container = new Container();
AppFactory::setContainer($container);
$container->set('db', function () {
$dsn = 'mysql:host=localhost;dbname=slim_demo;charset=utf8mb4';
return new PDO($dsn, 'root', '', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
});
$app = AppFactory::create();
The closure passed to set() only runs the first time something asks the container for
'db' — after that, the same PDO instance is handed back every time,
so you get exactly one connection per request instead of one per query.
Querying from a Route Handler
Inside a route closure, $this refers to the container, so pulling the connection out and
running a prepared statement looks almost identical to plain PHP:
<?php
$app->get('/users', function ($request, $response) {
$db = $this->get('db');
$stmt = $db->prepare('SELECT id, name, email FROM users ORDER BY id DESC LIMIT ?');
$stmt->bindValue(1, 20, PDO::PARAM_INT);
$stmt->execute();
$users = $stmt->fetchAll();
$response->getBody()->write(json_encode($users));
return $response->withHeader('Content-Type', 'application/json');
});
Everything about the query itself — the prepared statement, the placeholder, fetchAll()
— is exactly the PDO you already know. Slim just gave the handler a ready-to-use connection
instead of making it build one from scratch.
Query Builders and ORMs
If writing raw SQL for every query starts to feel tedious as a project grows, you're not stuck with
PDO forever. Composer packages like illuminate/database (Eloquent, usable outside
Laravel) or Cycle ORM can be added
the same way any other dependency is — a composer require away — and wired
into the container exactly like the PDO example above.