What is a router?
In an MVC (Model-View-Controller) application, routing is the mechanism that determines how an incoming request from a client (typically a web browser) is handled by the application. It maps URLs to specific controllers and actions/methods within those controllers.
This process allows the application to respond appropriately to different types of requests by executing the corresponding business logic and returning the correct view or response.
How does it work?
Routing handles the following in the application:
Request Handling: When a user makes a request to a web application (e.g., accessing a URL), the routing component of the MVC framework intercepts the request.
Route Mapping: The routing component uses predefined routes to map the URL to a specific controller and action. Routes are typically defined in a routing configuration file or within the application code.
Controller and Action Invocation: Based on the route mapping, the framework instantiates the appropriate controller and invokes the specified action method on that controller.
Model Interaction: The controller action interacts with the model to retrieve or manipulate data.
View Rendering: The controller action then passes data to the view, which is responsible for generating the user interface. The view renders the final HTML (or other formats) and sends it back to the client’s browser.
Ideally, we can end up with something like this:
$router->get('/home', 'StaticController@index');
$router->get('/about', 'StaticController@about');
$router->post('/articles', 'ArticlesController@index');
We’ll cover the handling of the controllers in an upcoming article soon.
Here’s a quick and dirty example of a simplified routing class:
<?php
namespace App;
class Router
{
private $routes = [];
public function add($method, $path, $handler)
{
$this->routes[] = [
'method' => strtoupper($method),
'path' => $path,
'handler' => $handler
];
}
public function dispatch($method, $uri)
{
foreach ($this->routes as $route) {
if ($route['method'] == strtoupper($method) && $route['path'] == $uri) {
if (is_callable($route['handler'])) {
return call_user_func($route['handler']);
} elseif (is_string($route['handler'])) {
return $this->callController($route['handler']);
}
}
}
http_response_code(404);
echo '404 Not Found';
}
private function callController($handler)
{
list($controller, $action) = explode('@', $handler);
$controller = "App\\Controllers\\$controller";
if (class_exists($controller)) {
$controllerInstance = new $controller();
if (method_exists($controllerInstance, $action)) {
return call_user_func([$controllerInstance, $action]);
} else {
http_response_code(404);
echo "Action '$action' not found in controller '$controller'";
}
} else {
http_response_code(404);
echo "Controller '$controller' not found";
}
}
}
In the code above, we have an array to get the routes from a centralized routes file, the dispatch method handles our routes by calling in the appropriate method, and the callController method checks whether the method actually exists in the specified controller.
Note: you can use a standard Closure method instead of having to use a controller at all but it’s usually good practice to put the handler method in a controller.
Finally, we can accomplish something like this in our routes file:
require_once "vendor/autoload.php";
use App\Routing\Router as Router;
$router = new Router();
$router->add('GET', '/', 'SiteController@index');
$router->add('GET', '/about', function(){
echo "This is the about page. <br>"
});