Pramnos Modern Routing Guide¶
The Routing Engine in Pramnos v1.2 supports both attribute-based and fluent API routing with parameter binding, groups, and middleware support.
Class: Pramnos\Routing\Router
Getting Started¶
Define Routes¶
// routes/web.php or routes/api.php
$router = \Pramnos\Routing\Router::getInstance();
// Simple GET route
$router->get('/users', 'UserController@index');
// GET with parameter
$router->get('/users/{id}', 'UserController@show');
// POST route
$router->post('/users', 'UserController@store');
// PATCH/PUT route
$router->patch('/users/{id}', 'UserController@update');
// DELETE route
$router->delete('/users/{id}', 'UserController@destroy');
// Multiple methods
$router->match(['get', 'post'], '/search', 'SearchController@handle');
// All HTTP methods
$router->any('/webhook', 'WebhookController@handle');
Route Parameters¶
// Simple parameter
$router->get('/users/{id}', 'UserController@show');
// Constrained parameter (regex)
$router->get('/posts/{id}', 'PostController@show')->where('id', '[0-9]+');
// Multiple constraints
$router->get('/files/{year}/{month}/{slug}', 'FileController@show')
->where('year', '[0-9]{4}')
->where('month', '[0-9]{2}')
->where('slug', '[a-z0-9-]+');
// Global constraints (apply to all routes)
$router->pattern('id', '[0-9]+');
$router->pattern('slug', '[a-z0-9-]+');
Named Routes¶
$router->get('/users/{id}', 'UserController@show')->name('users.show');
// Generate URL from name
$url = route('users.show', ['id' => 42]);
// → /users/42
Route Groups¶
Prefix & Middleware¶
$router->group([
'prefix' => 'admin',
'middleware' => ['auth', 'admin'],
], function ($router) {
$router->get('/dashboard', 'Admin/DashboardController@show');
$router->get('/users', 'Admin/UserController@index');
$router->post('/users', 'Admin/UserController@store');
});
// Routes:
// GET /admin/dashboard
// GET /admin/users
// POST /admin/users
Route Groups with Namespaces¶
$router->group(['namespace' => 'Api'], function ($router) {
$router->get('/users', 'UserController@index');
// Resolves to Api\UserController@index
});
Nested Groups¶
$router->group(['prefix' => 'api'], function ($router) {
$router->group(['prefix' => 'v1', 'middleware' => 'api'], function ($router) {
$router->get('/users', 'UserController@index');
});
});
// Route: GET /api/v1/users
Middleware¶
Apply Middleware¶
// Single route
$router->get('/profile', 'ProfileController@show')->middleware('auth');
// Multiple middleware
$router->post('/users', 'UserController@store')
->middleware(['auth', 'verified']);
// Entire group
$router->group(['middleware' => ['auth', 'csrf']], function ($router) {
$router->post('/settings', 'SettingsController@update');
});
// Exclude middleware
$router->get('/login', 'AuthController@login')
->withoutMiddleware(['csrf']); // CSRF not required for login form
Attribute-Based Routing¶
Route Attributes (PHP 8+)¶
<?php
namespace App\Controllers;
use Pramnos\Routing\Attributes\{Route, Middleware, Name};
class UserController extends \Pramnos\Application\Controller
{
#[Route('GET', '/users')]
#[Name('users.index')]
public function index()
{
// GET /users
}
#[Route('GET', '/users/{id}')]
#[Name('users.show')]
public function show($id)
{
// GET /users/{id}
}
#[Route('POST', '/users')]
#[Middleware('auth')]
public function store()
{
// POST /users (requires auth)
}
#[Route('PATCH', '/users/{id}')]
#[Middleware('auth')]
public function update($id)
{
// PATCH /users/{id}
}
}
Auto-Discovery of Routes¶
// Scan controllers for attributes
$router->discoverRoutes([
'path' => 'app/Controllers',
'namespace' => 'App\\Controllers',
]);
Route Model Binding¶
Implicit Binding¶
$router->get('/users/{user}', 'UserController@show');
// Automatically inject User model
class UserController extends \Pramnos\Application\Controller
{
public function show(\App\Models\User $user)
{
// $user is automatically loaded by ID from the URL
return view('users.show', ['user' => $user]);
}
}
Custom Key¶
Fallback & View Routes¶
Catch-All Route¶
Redirect Route¶
$router->redirect('/home', '/dashboard');
$router->redirectPermanent('/old-path', '/new-path'); // 301
View Route¶
// Render view directly without controller
$router->view('/about', 'pages.about');
// With data
$router->view('/contact', 'pages.contact', [
'email' => 'contact@example.com',
]);
Route Listing¶
View All Routes¶
php vendor/bin/pramnos route:list
# Output:
# GET /users UserController@index
# GET /users/{id} UserController@show
# POST /users UserController@store
Complete Example¶
// routes/web.php
$router = \Pramnos\Routing\Router::getInstance();
// Public routes
$router->get('/', 'HomeController@show')->name('home');
$router->get('/about', 'PageController@show', ['page' => 'about'])->name('about');
$router->get('/contact', 'ContactController@show')->name('contact');
$router->post('/contact', 'ContactController@store');
// Authentication routes
$router->group(['middleware' => 'guest'], function ($router) {
$router->get('/login', 'Auth/LoginController@show')->name('login');
$router->post('/login', 'Auth/LoginController@store');
$router->get('/register', 'Auth/RegisterController@show')->name('register');
$router->post('/register', 'Auth/RegisterController@store');
});
// Protected routes
$router->group(['middleware' => ['auth', 'verified']], function ($router) {
$router->get('/dashboard', 'DashboardController@show')->name('dashboard');
$router->post('/logout', 'Auth/LogoutController@store')->name('logout');
// User profile
$router->get('/profile', 'ProfileController@show')->name('profile.show');
$router->patch('/profile', 'ProfileController@update')->name('profile.update');
});
// Admin routes
$router->group(['prefix' => 'admin', 'middleware' => ['auth', 'admin']], function ($router) {
$router->get('/', 'Admin/DashboardController@show')->name('admin.dashboard');
$router->resource('users', 'Admin/UserController'); // REST resource
$router->resource('posts', 'Admin/PostController');
});
// API routes
$router->group(['prefix' => 'api/v1', 'middleware' => 'api'], function ($router) {
$router->get('/users', 'Api/UserController@index');
$router->get('/users/{id}', 'Api/UserController@show')->where('id', '[0-9]+');
$router->post('/users', 'Api/UserController@store')->middleware('auth:api');
});
REST Resource Routes¶
Auto-Generate CRUD Routes¶
// Generates all 7 RESTful routes
$router->resource('posts', 'PostController');
// Generated routes:
// GET /posts PostController@index
// GET /posts/create PostController@create
// POST /posts PostController@store
// GET /posts/{id} PostController@show
// GET /posts/{id}/edit PostController@edit
// PATCH /posts/{id} PostController@update
// DELETE /posts/{id} PostController@destroy
Customize Resource Routes¶
$router->resource('comments', 'CommentController')
->only('index', 'show', 'store', 'destroy') // Exclude create/edit
->except(['create', 'edit']) // Same as above
->names('comments.list', 'comments.view'); // Custom names
Route Groups¶
Programmatic groups — Router::group()¶
$router->group([
'prefix' => '/api/v1',
'middleware' => [ApiAuthMiddleware::class, ThrottleMiddleware::class],
'permissions' => ['api:access'],
'name' => 'api.v1.',
], function (\Pramnos\Routing\Router $r): void {
$r->get('/users', [UserController::class, 'index'])->name('users.index');
$r->post('/users', [UserController::class, 'store'])->name('users.store');
$r->get('/users/{id}', [UserController::class, 'show'])->name('users.show');
});
// Registered routes:
// GET /api/v1/users named api.v1.users.index
// POST /api/v1/users named api.v1.users.store
// GET /api/v1/users/{id} named api.v1.users.show
// URL generation still works:
echo $router->route('api.v1.users.show', ['id' => 42]); // /api/v1/users/42
Supported attributes:
| Key | Type | Description |
|---|---|---|
prefix |
string |
URI prefix prepended to every route URI |
middleware |
array |
Middleware prepended before each route's own middleware |
permissions |
array |
Permission scopes merged with each route's own permissions |
name |
string |
Logical name prefix prepended to every named route |
Nested groups¶
$router->group(['prefix' => '/api', 'name' => 'api.'], function (Router $r): void {
$r->group(['prefix' => '/v2', 'name' => 'v2.'], function (Router $r): void {
$r->get('/items', fn() => ...)->name('items.index');
// → GET /api/v2/items named api.v2.items.index
});
$r->get('/status', fn() => ...);
// → GET /api/status (only outer prefix)
});
Middleware ordering¶
#[RouteGroup] attribute¶
Apply group attributes declaratively on a controller class. RouteDiscovery reads the attribute and wraps all #[Route] methods in a Router::group() call:
use Pramnos\Routing\Attributes\Route;
use Pramnos\Routing\Attributes\RouteGroup;
#[RouteGroup(
prefix: '/api/v1',
middleware: [ApiAuthMiddleware::class],
permissions: ['api:access'],
name: 'api.v1.',
)]
class UserController
{
#[Route('/users', methods: 'GET', name: 'users.index')]
#[Route('/users', methods: 'POST', name: 'users.store')]
public function index(): void { ... }
#[Route('/users/{id}', methods: 'GET', name: 'users.show')]
public function show(int $id): void { ... }
}
#[RouteGroup] constructor parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
prefix |
string |
'' |
URI prefix |
middleware |
array |
[] |
Middleware FQCN strings |
permissions |
array |
[] |
Permission scopes |
name |
string |
'' |
Name prefix |
Reference¶
For related guides:
- Pramnos_Framework_Guide.md — Middleware pipeline, global middleware
- Pramnos_API_Guide.md — API middleware, CORS, authentication
Topics covered:
- Route definition with all HTTP methods
- Parameter binding and constraints
- Named routes and URL generation
- Route groups with prefixes, middleware, permissions, and name prefixes
- Attribute-based routing discovery (
#[Route],#[RouteGroup]) - Resource routes and REST conventions