V3 Routes Adaptor Guide
Introduction
The V3RoutesAdaptor utility enables combining multiple V3 controllers within a single route and displaying their outputs in a unified view. This utility is designed with a Single Page Application (SPA) mindset, facilitating future migrations to frameworks like React or Vue.
This approach allows for modular controller organization while maintaining a unified frontend experience, making future transitions to modern JavaScript frameworks much smoother.
Basic Usage
To use this utility, call the createRoute method in your mg_route file as follows:
use App\Utilities\V3RoutesAdaptor;
use App\Utilities\V3RouteControllerCollection;
V3RoutesAdaptor::createRoute(
method: 'GET', // HTTP method
controllers: new V3RouteControllerCollection([...]), // Controller collection
url: 'your/route/path', // Route path
viewPath: 'path.to.your.view' // View path
)
Parameters
- Method
- Controllers
- URL
- View Path
method: 'GET'
The HTTP method for the route. Common values include:
GET- For retrieving dataPOST- For creating new resourcesPUT- For updating existing resourcesDELETE- For removing resources
This parameter determines how the route will respond to different types of HTTP requests.
controllers: new V3RouteControllerCollection([
// Controller DTOs go here
])
A collection of controller DTOs that will be executed when the route is accessed. Each controller in the collection will be processed in sequence, and their results will be combined for the view.
See the "Defining Controllers" section below for details on how to create controller DTOs.
url: 'products/{category}/{id}'
The URL pattern for the route. This follows Laravel's routing syntax and can include:
- Static segments:
products - Dynamic parameters:
{id},{category} - Optional parameters:
{id?}
Examples:
products- Simple static routeproducts/{id}- Route with a dynamic ID parameterusers/{user}/posts/{post}- Nested resources
viewPath: 'products.show'
The path to the Blade view that will be used to render the combined results from all controllers. This follows Laravel's dot notation for view paths.
Examples:
products.index- Resolves toresources/views/products/index.blade.phpadmin.users.show- Resolves toresources/views/admin/users/show.blade.php
Defining Controllers with V3RouteControllerDTO
Each controller must be defined using a V3RouteControllerDTO object, which includes the following properties:
Properties Explained
- controller: The controller class name (with namespace)
- controllerMethod: The controller method to be called
- controllerMethodArgs: (Optional) A closure that returns an array of arguments to be passed to the controller method
- v3Params: (Optional) A closure that returns additional parameters to modify the request
Usage Examples
- Basic Controller
- Dynamic Parameters
- V3 Filters
- Complete Example
Simple List Display
This is the simplest use case, calling the index method of a controller without any parameters:
use App\Utilities\V3RouteControllerDTO;
use App\Http\Controllers\UserController;
new V3RouteControllerDTO(
controller: UserController::class,
controllerMethod: 'index'
)
This will call the index method of the UserController class with no additional parameters.
Controller with Dynamic Parameters
When your controller method requires parameters from the route or request:
use App\Utilities\V3RouteControllerDTO;
use App\Http\Controllers\ProductController;
new V3RouteControllerDTO(
controller: ProductController::class,
controllerMethod: 'show',
controllerMethodArgs: function() {
return [
request()->route('id'),
request()
];
}
)
The controllerMethodArgs closure returns an array of arguments that will be passed to the show method of the ProductController in the exact order they are defined.
Controller with V3 Filters
When you need to modify the request parameters for V3 API filtering:
use App\Utilities\V3RouteControllerDTO;
use App\Http\Controllers\SearchController;
new V3RouteControllerDTO(
controller: SearchController::class,
controllerMethod: 'index',
v3Params: function() {
$filters = request()->all();
if (request()->filled('search')) {
$search = request('search');
$filters['search'] = "title:$search;description:$search";
$filters['searchFields'] = "title:like;description:like";
}
return $filters;
}
)
The v3Params closure allows you to customize the V3 API filters based on the current request context.
Complete Route with Multiple Controllers
Combining multiple controllers in a single route:
use App\Utilities\V3RoutesAdaptor;
use App\Utilities\V3RouteControllerCollection;
use App\Utilities\V3RouteControllerDTO;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\CategoryController;
use App\Http\Controllers\ReviewController;
V3RoutesAdaptor::createRoute(
method: 'GET',
controllers: new V3RouteControllerCollection([
// Get product details
new V3RouteControllerDTO(
controller: ProductController::class,
controllerMethod: 'show',
controllerMethodArgs: function() {
return [request()->route('id')];
}
),
// Get related categories
new V3RouteControllerDTO(
controller: CategoryController::class,
controllerMethod: 'index',
v3Params: function() {
return [
'filter' => 'product_id:' . request()->route('id'),
'includes' => 'products'
];
}
),
// Get product reviews
new V3RouteControllerDTO(
controller: ReviewController::class,
controllerMethod: 'index',
v3Params: function() {
return [
'filter' => 'product_id:' . request()->route('id'),
'sort' => '-created_at',
'limit' => 5
];
}
)
]),
url: 'products/{id}',
viewPath: 'products.show'
)
This example creates a product detail page that combines data from three different controllers: product details, related categories, and recent reviews.
How It Works
When a route created with V3RoutesAdaptor is accessed:
- The system processes each controller in the collection sequentially
- Results from all controllers are merged into a single data array
- The combined data is passed to the specified Blade view
- The view renders the complete page with all the data
This approach maintains separation of concerns while providing a unified user experience.
Best Practices
- Organize by Domain: Group controllers by domain or feature rather than by technical function
- Limit Controller Count: Try to keep the number of controllers per route reasonable (3-5 max) for maintainability
- Use Descriptive Names: Name your controller methods clearly to indicate their purpose
- Consider Performance: Be mindful of the performance impact of executing multiple controllers for a single route
- Handle Errors Consistently: Implement consistent error handling across all controllers
Conclusion
The V3RoutesAdaptor utility provides a powerful way to combine multiple controllers in a single route, facilitating a more modular and maintainable codebase while preparing for potential future migrations to modern JavaScript frameworks.