The neuron router is a lightweight router/dispatcher is the vein of Ruby's Sinatra or Python's Flask. It allows for a very quick method for creating an app using restful routes or to add them to an existing application.
- Easily map restful http requests to functions.
- Extract one or many variables from routes using masks.
- Create custom 404 responses.
Install php composer from https://getcomposer.org/
Install the neuron routing component:
composer require neuron-php/routing
This example .htaccess file shows how to get and pass the route to the example application.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?route=$1 [L,QSA]
Here is an example of a fully functional application that processes several routes including one with a variable.
<?php
require_once 'vendor/autoload.php';
Route::get( '/',
function()
{
echo 'Home Page';
}
);
Route::get( '/about',
function()
{
echo 'About Page';
}
);
Route::get( '/test/:name',
function( $parameters )
{
echo "Name = $parameters[name]";
}
);
Route::get( '/404',
function( $parameters )
{
echo "No route found for $parameters[route]";
}
);
$Get = new \Neuron\Data\Filter\Get();
$Server = new \Neuron\Data\Filter\Server();
Route::dispatch(
[
'route' => $Get->filterScalar( 'route' ),
'type' => $Server->filterScalar( 'METHOD' )
]
);
If present, the extra element is merged into the parameters array before it is passed to the routes closure.
Modern PHP 8+ attribute-based routing allows you to define routes directly on controller methods using PHP attributes, providing a modern alternative to YAML configuration files.
use Neuron\Routing\Attributes\Get;
class HomeController
{
#[Get('/')]
public function index()
{
return 'Hello World';
}
}use Neuron\Routing\Attributes\Get;
use Neuron\Routing\Attributes\Post;
use Neuron\Routing\Attributes\Put;
use Neuron\Routing\Attributes\Delete;
class UsersController
{
#[Get('/users')]
public function index() { }
#[Get('/users/:id')]
public function show(int $id) { }
#[Post('/users')]
public function store() { }
#[Put('/users/:id')]
public function update(int $id) { }
#[Delete('/users/:id')]
public function destroy(int $id) { }
}#[Get('/admin/users', name: 'admin.users.index', filters: ['auth'])]
public function index() { }
#[Post('/admin/users', name: 'admin.users.store', filters: ['auth', 'csrf'])]
public function store() { }Apply common settings to all routes in a controller:
use Neuron\Routing\Attributes\RouteGroup;
use Neuron\Routing\Attributes\Get;
use Neuron\Routing\Attributes\Post;
#[RouteGroup(prefix: '/admin', filters: ['auth'])]
class AdminController
{
#[Get('/dashboard')] // Becomes /admin/dashboard with 'auth' filter
public function dashboard() { }
#[Post('/users', filters: ['csrf'])] // Becomes /admin/users with ['auth', 'csrf'] filters
public function createUser() { }
}#[Get('/api/v1/users')]
#[Get('/api/v2/users')]
public function getUsers()
{
// Handle both API versions
}Add controller paths to your config/neuron.yaml:
routing:
controller_paths:
- path: 'src/Controllers'
namespace: 'App\Controllers'
- path: 'src/Admin/Controllers'
namespace: 'App\Admin\Controllers'You can use both YAML routes and attribute routes together:
- YAML routes: Legacy routes, package-provided routes
- Attribute routes: New application routes
The MVC Application will load both automatically.
- Co-location: Routes live with controller logic
- Type Safety: IDE autocomplete and validation
- Refactor-Friendly: Routes update when controllers change
- No Sync Issues: Can't have orphaned routes
- Modern Standard: Used by Symfony, Laravel, ASP.NET, Spring Boot
- Self-Documenting: Route definition IS the documentation
Route scanning uses PHP Reflection, which could be slow. For production:
- Routes are scanned once during application initialization
- The Router caches RouteMap objects in memory
- No reflection happens during request handling
- Future: Add route caching to file for zero-cost production routing
Before (YAML):
# routes.yaml
home:
method: GET
route: /
controller: App\Controllers\Home@indexAfter (Attributes):
class Home
{
#[Get('/', name: 'home')]
public function index() { }
}See tests/unit/RouteScannerTest.php for working examples of basic route definition, route groups with prefixes, filter composition, and multiple routes per method.
The routing component includes a powerful rate limiting system with multiple storage backends and flexible configuration options.
use Neuron\Routing\Router;
use Neuron\Routing\Filters\RateLimitFilter;
use Neuron\Routing\RateLimit\RateLimitConfig;
$router = Router::instance();
// Create rate limit configuration
$config = new RateLimitConfig([
'enabled' => true,
'storage' => 'redis', // Options: redis, file, memory (testing only)
'requests' => 100, // Max requests per window
'window' => 3600 // Time window in seconds (1 hour)
]);
// Create and register the filter
$rateLimitFilter = new RateLimitFilter($config);
$router->registerFilter('rate_limit', $rateLimitFilter);
// Apply globally to all routes
$router->addFilter('rate_limit');
// Or apply to specific routes
$router->get('/api/data', $handler, 'rate_limit');// Array configuration
$config = new RateLimitConfig([
'enabled' => true,
'storage' => 'redis',
'requests' => 100,
'window' => 3600,
'redis_host' => '127.0.0.1',
'redis_port' => 6379,
'file_path' => 'cache/rate_limits'
]);Best for distributed systems and high-traffic applications:
$config = new RateLimitConfig([
'storage' => 'redis',
'redis_host' => '127.0.0.1',
'redis_port' => 6379,
'redis_database' => 0,
'redis_prefix' => 'rate_limit_',
'redis_auth' => 'password', // Optional
'redis_persistent' => true // Use persistent connections
]);Simple solution for single-server deployments:
$config = new RateLimitConfig([
'storage' => 'file',
'file_path' => 'cache/rate_limits' // Directory for rate limit files
]);For unit tests and development:
$config = new RateLimitConfig([
'storage' => 'memory' // Data lost when PHP process ends
]);$filter = new RateLimitFilter(
$config,
'ip',
['192.168.1.100', '10.0.0.1'], // Whitelist - no limits
['45.67.89.10'] // Blacklist - stricter limits (1/10th)
);Rate limit exceeded responses include appropriate headers:
X-RateLimit-Limit: Maximum requests allowedX-RateLimit-Remaining: Requests remainingX-RateLimit-Reset: Unix timestamp when limit resetsRetry-After: Seconds until retry allowed
The response format (JSON/HTML) is automatically determined from the Accept header.
// Different limits for different endpoints
$publicConfig = new RateLimitConfig([
'enabled' => true,
'storage' => 'redis',
'requests' => 10,
'window' => 60 // 10 requests per minute
]);
$apiConfig = new RateLimitConfig([
'enabled' => true,
'storage' => 'redis',
'requests' => 1000,
'window' => 3600 // 1000 requests per hour
]);
$router->registerFilter('public_limit', new RateLimitFilter($publicConfig));
$router->registerFilter('api_limit', new RateLimitFilter($apiConfig));
// Apply different limits
$router->get('/public/search', $searchHandler, 'public_limit');
$router->get('/api/users', $usersHandler, 'api_limit');You can read more about the Neuron components at neuronphp.com