Action classes
While handlers are functions inside config/routes.php, the file grows with every route. A handler is moved into a separate class — an action. One class is responsible for one route, and the routes file keeps a single line.
Where actions live
Actions go into the src/Action/ folder. Slim has no command to create them: make the folder and the file by hand.
The first action
// src/Action/HomeAction.php
namespace App\Action;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
final class HomeAction
{
public function __invoke(Request $request, Response $response): Response
{
$response->getBody()->write('Blog home page');
return $response;
}
}__invoke is a special PHP method: an object that has it can be called like a function. The arguments are the same as for a handler function.
Using it in a route
In config/routes.php the class name replaces the function:
// config/routes.php
use App\Action\HomeAction;
use Slim\App;
return function (App $app): void {
$app->get('/', HomeAction::class)->setName('home');
};Open http://localhost:8080 — the page is the same, but the handler code now has its own file. Slim creates the class object itself when a request arrives.
An action with a placeholder
Placeholders arrive as the third argument, just as in a function:
// src/Action/ShowPostAction.php
namespace App\Action;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
final class ShowPostAction
{
public function __invoke(Request $request, Response $response, array $args): Response
{
$response->getBody()->write('Post #' . (int) $args['id']);
return $response;
}
}// config/routes.php
$app->get('/posts/{id:[0-9]+}', ShowPostAction::class)->setName('posts.show');The address /posts/5 prints "Post #5". Remember to add use App\Action\ShowPostAction; at the top of the routes file.
Naming
An action name answers the question "what does the route do":
| Route | Class |
|---|---|
GET /posts | ListPostsAction |
GET /posts/{id} | ShowPostAction |
POST /posts | CreatePostAction |
A controller instead of actions
If a controller — one class with several methods — feels more familiar, the route is written as an array of the class name and the method name:
// config/routes.php
$app->get('/posts', [PostController::class, 'index']);
$app->get('/posts/{id:[0-9]+}', [PostController::class, 'show']);The index and show methods take the same arguments as __invoke. The course uses actions: each class is short and receives only what its route needs.
Common mistake
An action that parses the request, runs database queries and builds HTML all by itself turns into a "fat" class. Keep three steps in an action: take data from the request, call another class that does the work, and build the response. How to pass such classes into an action is shown in the next lesson.