Derafu Routing - Guía de Uso Completa
Derafu Routing es una biblioteca de enrutamiento PHP flexible que utiliza una arquitectura basada en parsers. En lugar de tener un router monolítico, separa la lógica de enrutamiento en parsers especializados, cada uno manejando diferentes tipos de rutas.
- Instalación
- Conceptos Básicos
- Tipos de Rutas
- Usando el Router
- El Dispatcher
- Uso Avanzado
- Mejores Prácticas
Instalación
composer require derafu/routing
Conceptos Básicos
Arquitectura de Parsers
El sistema de enrutamiento está construido alrededor de parsers especializados:
- StaticParser: Maneja coincidencias exactas de rutas.
- DynamicParser: Procesa rutas con parámetros.
- FileSystemParser: Mapea URLs a archivos físicos.
Cada parser implementa la interfaz ParserInterface
:
interface ParserInterface {
public function parse(string $uri, array $routes): ?RouteMatchInterface;
public function supports(RouteInterface $route): bool;
}
Tipos de Rutas
Rutas Estáticas
La forma más simple de enrutamiento, manejada por StaticParser
:
$router = new Router([new StaticParser()]);
$router->addRoute('/about', 'PagesController@action');
$router->addRoute('/contacto', 'ContactoController@show');
Rutas Dinámicas
Manejadas por DynamicParser
, soportando varios tipos de parámetros:
$router->addParser(new DynamicParser());
// Parámetro básico.
$router->addRoute('/usuarios/{id}', 'UsuarioController@show');
// Validación con expresiones regulares.
$router->addRoute('/usuarios/{id:\d+}', 'UsuarioController@show');
// Parámetros opcionales.
$router->addRoute('/blog/{año?}', 'BlogController@index');
// Múltiples parámetros.
$router->addRoute('/blog/{año}/{mes?}', 'BlogController@archivo');
// Patrones complejos.
$router->addRoute('/usuarios/{username:[a-z0-9_-]+}', 'UsuarioController@perfil');
Rutas del Sistema de Archivos
El FileSystemParser
mapea URLs a archivos reales:
$parser = new FileSystemParser(
directories: [__DIR__ . '/paginas'],
extensions: ['.html.twig', '.md']
);
$router->addParser($parser);
Estructura de directorios:
paginas/
├── about.md # Coincide con /about
├── contacto.twig # Coincide con /contacto
└── blog/
├── post-1.md # Coincide con /blog/post-1
└── post-2.md # Coincide con /blog/post-2
Usando el Router
Configuración Básica
use Derafu\Routing\Router;
use Derafu\Routing\Parser\StaticParser;
use Derafu\Routing\Parser\DynamicParser;
$router = new Router([
new StaticParser(),
new DynamicParser(),
]);
Agregando Rutas
// Manejador tipo string (Controlador@acción).
$router->addRoute('/usuarios', 'UsuarioController@index');
// Manejador tipo Closure.
$router->addRoute('/api/datos', function($params) {
return ['datos' => 'valor'];
});
// Manejador tipo array.
$router->addRoute('/blog', [
'controller' => 'BlogController',
'action' => 'listar'
]);
// Rutas con nombre y parámetros.
$router->addRoute(
route: '/usuarios/{id}',
handler: 'UsuarioController@show',
name: 'usuario.show',
parameters: ['activo' => true]
);
Coincidencia de Rutas
try {
$match = $router->match('/usuarios/123');
// $match->getHandler(): Retorna el manejador de la ruta.
// $match->getParameters(): Retorna los parámetros de la ruta.
// $match->getName(): Retorna el nombre de la ruta si está definido.
} catch (RouteNotFoundException $e) {
// Manejar 404.
}
El Dispatcher
El dispatcher maneja la ejecución de las rutas coincidentes:
$dispatcher = new Dispatcher([
'md' => function($file, $params) {
// Renderizar archivo markdown.
return parseMarkdown(file_get_contents($file));
},
'twig' => function($file, $params) {
// Renderizar plantilla Twig.
return $twig->render($file, $params);
}
]);
$resultado = $dispatcher->dispatch($match);
Nota: Este es un dispatcher muy básico, se debe implementar uno propio.
Uso Avanzado
Ejemplo de Parser Personalizado
class RegexParser implements ParserInterface
{
public function parse(string $uri, array $routes): ?RouteMatchInterface
{
foreach ($routes as $route) {
if (!$this->supports($route)) {
continue;
}
// Lógica personalizada de coincidencia regex
if (preg_match($route->getPattern(), $uri, $matches)) {
return new RouteMatch(
$route->getHandler(),
$matches
);
}
}
return null;
}
public function supports(RouteInterface $route): bool
{
// Define qué rutas maneja este parser
return str_starts_with($route->getPattern(), '#');
}
}
Mejores Prácticas
-
Orden de los Parsers: Agregar parsers en orden de especificidad.
- StaticParser primero (más rápido, más específico).
- DynamicParser después.
- FileSystemParser al final (más flexible, pero más lento).
-
Organización de Rutas: Agrupar rutas relacionadas.
// Gestión de usuarios $router->addRoute('/usuarios', 'UsuarioController@index'); $router->addRoute('/usuarios/{id}', 'UsuarioController@show'); // Sistema de blog $router->addRoute('/blog', 'BlogController@index'); $router->addRoute('/blog/{slug}', 'BlogController@show');
-
Validación de Parámetros: Usar restricciones regex para mejor seguridad.
// Asegurar que ID sea numérico. $router->addRoute('/usuarios/{id:\d+}', 'UsuarioController@show'); // Validar formato de nombre de usuario. $router->addRoute('/usuarios/{username:[a-z0-9_-]+}', 'UsuarioController@perfil');
-
Manejo de Errores: Siempre envolver coincidencias en try-catch.
try { $match = $router->match($uri); $resultado = $dispatcher->dispatch($match); } catch (RouteNotFoundException $e) { // Manejar 404. } catch (DispatcherException $e) { // Manejar errores del dispatcher. }