1. Go to this page and download the library: Download sodaho/php-router library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
sodaho / php-router example snippets
use Sodaho\Router\Router;
use Sodaho\Router\Response;
$router = Router::create();
$router->loadRoutes(__DIR__ . '/routes.php');
$router->run();
use Sodaho\Router\RouteCollector;
return function (RouteCollector $r) {
$r->get('/users', [UserController::class, 'index']);
$r->get('/users/{id:int}', [UserController::class, 'show']);
$r->post('/users', [UserController::class, 'store']);
};
use Sodaho\Router\Response;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class UserController
{
public function show(ServerRequestInterface $request, int $id): ResponseInterface
{
$user = ['id' => $id, 'name' => 'John'];
return Response::success($user);
}
}
// Option A: Named arguments (recommended)
public function show(ServerRequestInterface $request, int $id): ResponseInterface
{
// $id is already typed and validated
}
// Option B: From request attributes
public function show(ServerRequestInterface $request): ResponseInterface
{
$id = $request->getAttribute('id');
}
$r->group('/api', function (RouteCollector $r) {
$r->group('/v1', function (RouteCollector $r) {
$r->get('/users', [UserController::class, 'index']);
});
});
// → /api/v1/users
use Psr\Http\Server\MiddlewareInterface;
// Per route
$r->get('/dashboard', [DashboardController::class, 'index'])
->middleware(AuthMiddleware::class);
// Multiple middleware
$r->get('/admin', [AdminController::class, 'index'])
->middleware([AuthMiddleware::class, AdminMiddleware::class]);
// Middleware group
$r->middlewareGroup([AuthMiddleware::class, LogMiddleware::class], function ($r) {
$r->get('/profile', [ProfileController::class, 'show']);
$r->put('/profile', [ProfileController::class, 'update']);
});
class OwnershipMiddleware implements MiddlewareInterface
{
public function process($request, $handler): ResponseInterface
{
$orderId = $request->getAttribute('id'); // Available!
// ... ownership check
return $handler->handle($request);
}
}
// run() for simple apps
$router->run();
// handle() for PSR-15 integration
$request = $serverRequestFactory->fromGlobals();
$response = $router->handle($request); // Returns ResponseInterface
// Emit response yourself
(new SapiEmitter())->emit($response);
use Psr\Container\ContainerInterface;
$router = Router::create()
->setContainer($container) // Any PSR-11 container
->loadRoutes(__DIR__ . '/routes.php');
// Controllers are resolved via container if available
// Otherwise instantiated directly
use Sodaho\Router\Exception\RouterException;
use Sodaho\Router\Exception\NotFoundException;
use Sodaho\Router\Exception\MethodNotAllowedException;
use Sodaho\Router\Exception\RouteNotFoundException;
use Sodaho\Router\Exception\DuplicateRouteException;
use Sodaho\Router\Exception\CacheException;
try {
$router->run();
} catch (RouterException $e) {
// Catches all router exceptions
echo $e->getMessage();
echo $e->getDebugMessage(); // Additional debug info
}
// Default: strict (exact match)
$r->get('/users', $handler); // Only matches /users
$r->get('/users/', $handler); // Only matches /users/
// Ignore mode: /users matches both /users and /users/
$router = Router::create(['trailingSlash' => 'ignore']);
// API routes first
$r->group('/api', function ($r) {
$r->get('/users', [UserController::class, 'index']);
});
// Catch-all for Vue Router (history mode)
$r->get('/{any:any}', [PageController::class, 'index']);
class PageController
{
public function index($request): ResponseInterface
{
return Response::html(file_get_contents('public/index.html'));
}
}
use Sodaho\Router\Response;
use Sodaho\Router\Service\RfcResponder;
// RFC 7807 Problem Details format
Response::setResponder(new RfcResponder('https://api.example.com/errors'));
// Error responses now use RFC 7807:
// {
// "type": "https://api.example.com/errors/not-found",
// "title": "User not found",
// "status": 404,
// "detail": "User with ID 123 not found"
// }
use Sodaho\Router\Contract\ResponderInterface;
class XmlResponder implements ResponderInterface
{
public function formatSuccess(mixed $data, ?string $message = null, ?array $meta = null): array
{
// Return array that will be converted to XML
}
public function formatError(string $message, ?string $code = null, ?array $details = null): array
{
// Return array for error responses
}
public function getContentType(): string
{
return 'application/xml'; // Used for 4xx/5xx responses
}
public function getSuccessContentType(): string
{
return 'application/xml'; // Used for 2xx responses
}
}
// Option 1: Use a CSRF middleware
$r->middlewareGroup([CsrfMiddleware::class], function ($r) {
$r->post('/users', [UserController::class, 'store']);
$r->delete('/users/{id}', [UserController::class, 'destroy']);
});
// Option 2: For SPAs - use SameSite cookies + custom header
// Frontend sends: X-Requested-With: XMLHttpRequest
// Backend validates header presence
// {id:int} ensures $id is an integer, but NOT that:
// - The user exists
// - The current user can access it
// - The ID is within valid range
public function show(ServerRequestInterface $request, int $id): ResponseInterface
{
// Always validate business logic!
$user = $this->userRepository->find($id);
if ($user === null) {
return Response::notFound('User', $id);
}
if (!$this->canAccess($request, $user)) {
return Response::forbidden();
}
return Response::success($user);
}