Installation:
composer require poshtive/router
Publish config (optional but recommended for customization):
php artisan vendor:publish --provider="Poshtive\Router\RouterServiceProvider" --tag="config"
First Use Case:
Define a controller with attributes in app/Http/Controllers/.
Example: UserController.php
use Poshtive\Router\Attributes\Route;
class UserController {
#[Route('/users', methods: ['GET'])]
public function index() { ... }
#[Route('/users/{user}', methods: ['GET'])]
public function show(User $user) { ... }
}
Run:
php artisan route:discover
Verify: Check routes with:
php artisan route:list
Convention-Based Discovery:
app/Http/Controllers/ (default).#[Route] attributes to define routes.#[Route('/posts', methods: ['GET'])]
#[Route('/posts', methods: ['POST'])]
public function index() { ... }
#[Route('/posts/{post}', methods: ['GET'])]
#[Route('/posts/{post}', methods: ['PUT', 'DELETE'])]
public function update(Post $post) { ... }
Nested Resources:
app/Http/Controllers/Admin/).// app/Http/Controllers/Admin/UserController.php
#[Route('/users', methods: ['GET'])]
public function index() { ... }
Registers as /admin/users.Middleware and Constraints:
#[Route('/admin', middleware: ['auth.admin'])]
public function dashboard() { ... }
#[Route('/posts/{id}', where: ['id' => '[0-9]+'])]
public function show($id) { ... }
Model Binding:
public function show(User $user) { ... } // Automatically resolves from route parameter
Skipping Routes:
#[Route('/skip-me', skip: true)]
public function hidden() { ... }
Discovering Routes:
php artisan route:discover
config/router.php).Hybrid Approach:
Combine with Laravel’s traditional Route::get() for edge cases.
Example:
Route::get('/legacy', [LegacyController::class, 'action']);
Testing:
Use Route::getRoutes() to inspect discovered routes in tests:
public function test_discovered_routes() {
$routes = Route::getRoutes();
$this->assertCount(3, $routes);
}
Custom Directories:
Extend discovery to custom paths in config/router.php:
'paths' => [
app_path('Http/Controllers'),
app_path('Modules/*/Http/Controllers'),
],
Duplicate Routes:
skip: true or adjust attributes to resolve conflicts.Middleware Inheritance:
#[Route] on the class) does not inherit to methods.Model Binding Quirks:
Caching:
php artisan route:clear
PHP 8.3+ Requirement:
Skipped Routes Report:
Enable in config/router.php:
'report_skipped' => true,
Run discovery to see skipped routes in logs.
Route Dumping: Dump discovered routes to a file for debugging:
php artisan route:dump
Outputs to bootstrap/cache/route_dump.json.
Verbose Discovery: Run with verbose output:
php artisan route:discover --verbose
DRY Routes: Use inheritance for shared route logic:
#[Route('/base', middleware: ['auth'])]
class BaseController {
#[Route('/endpoint', methods: ['GET'])]
public function endpoint() { ... }
}
Dynamic Prefixes: Dynamically set prefixes via configuration or environment variables:
#[Route(config('router.admin_prefix').'/users')]
API Versioning: Leverage subdirectories for versioning:
app/Http/Controllers/
├── v1/
│ └── UserController.php
└── v2/
└── UserController.php
Configure paths in config/router.php to include both.
Performance:
config/router.php if using manual discovery:
'auto_discover' => false,
Extending Attributes:
Create custom attributes by extending Poshtive\Router\Attributes\Route:
#[Attribute(Attribute::TARGET_METHOD)]
class ApiRoute extends Route { ... }
How can I help you explore Laravel packages today?