1. Go to this page and download the library: Download bermudaphp/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/ */
// GET route for user listing
$routes->addRoute(RouteRecord::get('users.index', '/users', UsersController::class));
// POST route for creating new user
$routes->addRoute(RouteRecord::post('users.store', '/users', 'UsersController::store'));
// PUT route for full user update
$routes->addRoute(RouteRecord::put('users.update', '/users/[id]', 'UsersController::update'));
// PATCH route for partial user update
$routes->addRoute(RouteRecord::patch('users.patch', '/users/[id]', 'UsersController::patch'));
// DELETE route for user deletion
$routes->addRoute(RouteRecord::delete('users.destroy', '/users/[id]', 'UsersController::destroy'));
// Multiple methods for single route
$routes->addRoute(RouteRecord::any('users.resource', '/users/[id]', UsersController::class,
['GET', 'PUT', 'PATCH', 'DELETE']
));
// All HTTP methods (catch-all route)
$routes->addRoute(RouteRecord::any('api.catchall', '/api/[path:.*]', ApiController::class));
// Closure as handler
$routes->addRoute(RouteRecord::get('hello', '/hello/[name]', function(string $name) {
return "Hello, $name!";
}));
use Bermuda\Router\Middleware\{MatchRouteMiddleware, DispatchRouteMiddleware, RouteNotFoundHandler};
use Bermuda\Pipeline\Pipeline;
use Bermuda\MiddlewareFactory\MiddlewareFactory;
$pipeline = new Pipeline();
$factory = new MiddlewareFactory($container, $responseFactory);
// Middleware for route matching
$pipeline->pipe($factory->makeMiddleware(MatchRouteMiddleware::class));
// Create 404 handler
$notFoundHandler = new RouteNotFoundHandler($responseFactory);
// Middleware for route execution with fallback handler
$pipeline->pipe(new DispatchRouteMiddleware($notFoundHandler));
$response = $pipeline->handle($request);
use Bermuda\Router\Middleware\RouteNotFoundHandler;
// JSON response mode (default)
$notFoundHandler = new RouteNotFoundHandler(
$responseFactory,
exceptionMode: false,
customMessage: 'Requested resource not found'
);
// Example JSON response:
// {
// "error": "Not Found",
// "code": 404,
// "message": "Requested resource not found",
// "path": "/api/users/999",
// "method": "GET",
// "timestamp": "2024-12-25T10:30:00+00:00"
// }
// Exception mode
$notFoundHandler = new RouteNotFoundHandler(
$responseFactory,
exceptionMode: true // will throw RouteNotFoundException
);
// Dynamic mode switching via request attributes
$request = $notFoundHandler->withExceptionModeAttribute($request, true);
// Check current mode
$isExceptionMode = $notFoundHandler->getExceptionMode($request);
use Bermuda\Router\Middleware\{MatchRouteMiddleware, DispatchRouteMiddleware, RouteNotFoundHandler};
$pipeline = new Pipeline();
// 1. Try to find route
$pipeline->pipe(new MatchRouteMiddleware($middlewareFactory, $router));
// 2. Create 404 handler
$notFoundHandler = new RouteNotFoundHandler(
$responseFactory,
exceptionMode: false,
customMessage: 'API endpoint not found'
);
// 3. Execute found route or handle 404
$pipeline->pipe(new DispatchRouteMiddleware($notFoundHandler));
// Process request
$response = $pipeline->handle($request);
// With exceptionMode: true - exception handling
$notFoundHandler = new RouteNotFoundHandler($responseFactory, exceptionMode: true);
$pipeline->pipe(new DispatchRouteMiddleware($notFoundHandler));
try {
$response = $pipeline->handle($request);
} catch (RouteNotFoundException $e) {
// Custom exception handling (only works with exceptionMode: true)
$response = new JsonResponse([
'error' => 'Route not found',
'path' => $e->path,
'method' => $e->requestMethod
], 404);
}
// With exceptionMode: false (default) - automatic JSON response
$notFoundHandler = new RouteNotFoundHandler($responseFactory, exceptionMode: false);
$pipeline->pipe(new DispatchRouteMiddleware($notFoundHandler));
$response = $pipeline->handle($request);
// If route not found, RouteNotFoundHandler automatically returns JSON:
// HTTP 404 Not Found
// Content-Type: application/json; charset=utf-8
// {
// "error": "Not Found",
// "code": 404,
// "message": "The requested endpoint was not found.",
// "path": "/api/users/999",
// "method": "GET",
// "timestamp": "2024-12-25T10:30:00+00:00"
// }
use Bermuda\Router\Middleware\RouteMiddleware;
class UserController
{
public function show(ServerRequestInterface $request): ResponseInterface
{
// Get route data
$routeMiddleware = RouteMiddleware::fromRequest($request);
$route = $routeMiddleware->route;
// Access parameters
$userId = $request->getAttribute('id');
// or
$userId = $route->parameters->get('id');
// Route information
$routeName = $route->name;
$routePath = $route->path;
return new JsonResponse(['user_id' => $userId]);
}
}
use Bermuda\Router\Attribute\Route;
class UserController
{
#[Route('users.index', '/users', 'GET')]
public function index(): ResponseInterface
{
// Get user list
return new JsonResponse($this->userService->getAll());
}
#[Route('users.show', '/users/[id]', 'GET')]
public function show(ServerRequestInterface $request): ResponseInterface
{
$id = $request->getAttribute('id');
return new JsonResponse($this->userService->getById($id));
}
#[Route('users.store', '/users', 'POST', middleware: ['auth', 'validation'])]
public function store(ServerRequestInterface $request): ResponseInterface
{
$data = $request->getParsedBody();
$user = $this->userService->create($data);
return new JsonResponse($user, 201);
}
#[Route('users.update', '/users/[id]', 'PUT|PATCH', group: 'api')]
public function update(ServerRequestInterface $request): ResponseInterface
{
$id = $request->getAttribute('id');
$data = $request->getParsedBody();
$user = $this->userService->update($id, $data);
return new JsonResponse($user);
}
#[Route('users.destroy', '/users/[id]', 'DELETE', priority: 10)]
public function destroy(ServerRequestInterface $request): ResponseInterface
{
$id = $request->getAttribute('id');
$this->userService->delete($id);
return new JsonResponse(null, 204);
}
}
use Bermuda\Router\Locator\{RouteLocator, AttributeRouteLocator};
// Base locator (file-based or any other)
$baseLocator = new RouteLocator('/app/config/routes.php');
// Decorate with attribute locator
$attributeLocator = new AttributeRouteLocator($baseLocator);
// Pass context (if needed)
$attributeLocator->setContext([
'container' => $container,
'config' => $config
]);
// Get all routes (file + attributes)
$routes = $attributeLocator->getRoutes();
$router = Router::fromDnf($routes);
use Bermuda\ClassFinder\{ClassFinder, ClassNotifier};
use Bermuda\Router\Locator\AttributeRouteLocator;
use Bermuda\Router\Attribute\Route;
// Create locator
$baseLocator = new RouteLocator('/app/config/routes.php');
$attributeLocator = new AttributeRouteLocator($baseLocator);
// Find all classes in controllers directory
$finder = new ClassFinder();
$classes = $finder->find('src/Controllers/');
// Notify locator about found classes (locator filters classes with Route attributes)
$notifier = new ClassNotifier([$attributeLocator]);
$notifier->notify($classes);
// Get all routes
$routes = $attributeLocator->getRoutes();
$router = Router::fromDnf($routes);
use Bermuda\ClassFinder\{ClassFinder, ClassNotifier};
use Bermuda\Router\Locator\{RouteLocator, AttributeRouteLocator};
use Bermuda\Router\Attribute\Route;
// 1. Create base locator
$baseLocator = new RouteLocator(
filename: '/app/config/routes.php',
useCache: $_ENV['APP_ENV'] === 'production'
);
// 2. Create attribute locator as decorator
$attributeLocator = new AttributeRouteLocator($baseLocator);
$attributeLocator->setContext(['app' => $app, 'container' => $container]);
// 3. Find classes in various directories with exclusions
$finder = new ClassFinder();
$controllerClasses = $finder->find(
paths: [
'src/Controllers/', // Main controllers
'src/Api/', // API controllers
'app/Http/Controllers/' // Legacy controllers
],
exclude: ['src/Api/products'] // Exclude specific directory
);
// 4. Notify locator about found classes
// ClassFinder finds all classes in specified directories,
// then AttributeRouteLocator scans class methods for Route attributes
// and registers found methods as route handlers
$notifier = new ClassNotifier([$attributeLocator]);
$notifier->notify($controllerClasses);
// 5. Get all routes and create router
$routes = $attributeLocator->getRoutes();
$router = Router::fromDnf($routes);
// 6. Use in middleware pipeline
$pipeline = new Pipeline();
$pipeline->pipe(new MatchRouteMiddleware($middlewareFactory, $router));
$pipeline->pipe(new DispatchRouteMiddleware($notFoundHandler));
$response = $pipeline->handle($request);
// First define groups in base locator's routes.php file
/** @var Routes $routes */
$apiGroup = $routes->group('api', '/api');
$adminGroup = $routes->group('admin', '/admin');
// Now you can use these groups in attributes
class ApiController
{
#[Route('api.users.index', '/users', 'GET', group: 'api')]
public function getUsers(): ResponseInterface
{
return new JsonResponse($this->userService->getAll());
}
#[Route('api.users.store', '/users', 'POST', group: 'api', middleware: ['auth'])]
public function createUser(ServerRequestInterface $request): ResponseInterface
{
$data = $request->getParsedBody();
$user = $this->userService->create($data);
return new JsonResponse($user, 201);
}
}
// Group configuration can be added after route loading
$routes = $attributeLocator->getRoutes();
// Configure 'api' group after loading routes
$apiGroup = $routes->group('api');
$apiGroup->addMiddleware(CorsMiddleware::class);
$apiGroup->setTokens(['id' => '\d+']);
class RouteController
{
// Highest priority - special handling
#[Route('admin.special', '/admin/special/action', 'POST', priority: 100)]
public function specialAdminAction(): ResponseInterface
{
return new JsonResponse(['action' => 'special']);
}
// High priority - specific route
#[Route('user.profile', '/users/profile', 'GET', priority: 50)]
public function userProfile(): ResponseInterface
{
return new JsonResponse(['page' => 'profile']);
}
// Medium priority - route with parameter
#[Route('user.show', '/users/[id]', 'GET', priority: 10)]
public function showUser(): ResponseInterface
{
return new JsonResponse(['type' => 'user']);
}
// Normal priority - general route
#[Route('users.list', '/users', 'GET', priority: 0)]
public function listUsers(): ResponseInterface
{
return new JsonResponse(['type' => 'list']);
}
// Low priority - catch-all route (checked last)
#[Route('catch.all', '/[path:.*]', 'GET', priority: -10)]
public function catchAll(): ResponseInterface
{
return new JsonResponse(['type' => 'fallback']);
}
}
class ApiController
{
// v2 API - high priority
#[Route('api.v2.users', '/api/v2/users/[id]', 'GET', priority: 20)]
public function getUserV2(): ResponseInterface
{
return new JsonResponse(['version' => 'v2', 'features' => ['new_field']]);
}
// v1 API - medium priority
#[Route('api.v1.users', '/api/v1/users/[id]', 'GET', priority: 10)]
public function getUserV1(): ResponseInterface
{
return new JsonResponse(['version' => 'v1']);
}
// Fallback to v1 for requests without version - low priority
#[Route('api.users.fallback', '/api/users/[id]', 'GET', priority: 0)]
public function getUserFallback(): ResponseInterface
{
// Redirect to v1
return new JsonResponse(['version' => 'v1', 'deprecated' => true]);
}
}
// Regular routes - addition order determines priority
$routes->addRoute(RouteRecord::get('special', '/api/special', 'handler1')); // Checked first
$routes->addRoute(RouteRecord::get('generic', '/api/[path:.*]', 'handler2')); // Checked second
// Attribute routes - use priority parameter
#[Route('high', '/api/high', 'GET', priority: 100)] // Checked first
#[Route('low', '/api/low', 'GET', priority: 0)] // Checked second
use Bermuda\Router\CacheFileProvider;
// Setup routes
$routes = new Routes();
$routes->addRoute(RouteRecord::get('home', '/', 'HomeController'));
$routes->addRoute(RouteRecord::get('users.show', '/users/[id]', 'UsersController::show'));
// Create cache
$cacheProvider = new CacheFileProvider('/path/to/cache');
$routeData = $routes->toArray();
$cacheProvider->writeFile('routes', $routeData);
use Bermuda\Router\RoutesCache;
// Load cached routes
$cacheProvider = new CacheFileProvider('/path/to/cache');
$cachedData = $cacheProvider->readFile('routes');
$routes = new RoutesCache($cachedData);
$router = Router::fromDnf($routes);
// When creating routes with closures
$app = new Application();
$db = new Database();
$routes->addRoute(RouteRecord::get('users.index', '/users',
function() use ($app, $db) {
return $app->respond($db->users()->all());
}
));
// Save cache with context
$cacheProvider->writeFile('routes', $routes->toArray(), [
'app' => $app,
'db' => $db
]);
// Load with context - variables $app and $db will be available in cached file
$cachedData = $cacheProvider->readFile('routes');
$routes = new RoutesCache($cachedData);
// 1. Objects as handlers
$controller = new UserController();
$routes->addRoute(RouteRecord::get('users', '/users', $controller)); // Not cached
// 2. Closures with objects in use (without context)
$service = new UserService();
$routes->addRoute(RouteRecord::get('users', '/users',
function() use ($service) {
return $service->getUsers();
}
)); // Handler will be cached, but error will occur due to missing context // Undefined variable $service
// 3. Anonymous classes
$routes->addRoute(RouteRecord::get('test', '/test', new class {
public function handle() { return 'test'; }
})); // Anonymous class not cached