For the Invoice Management System application, we need to have routing of requests. Routing will help us to implement pages independently from each other and be rendered via a handler such as a PHP custom function or even better – An Action Controller PHP class. In this post, we are going to implement a simple router functionality so we can handle HTTP GET requests and render different information based on the page we are currently in.
The Request Class
The Request class provides a set of methods that are used in the Router class for identifying a callback function. With the help of the parse_url()
function we can get an associated array of elements from a current URL. The URL is located in the $_SERVER[‘REQUEST_URI’] global array.
<?php declare(strict_types=1);
namespace Invoice;
class Request
{
private array $server;
public function __construct()
{
$this->server = $_SERVER;
}
public function getServer(string $name): mixed
{
return $this->server[$name] ?? null;
}
public function getUri(): array
{
return parse_url($this->getServer('REQUEST_URI'));
}
public function getPath(): string
{
$uri = $this->getUri();
return $uri['path'];
}
}
The Router Class
The Router
class is responsible for finding or dispatching an incoming HTTP request and returning a callback function that is triggered in the App::run()
method. For simplicity, we are going to hard-code the list of routes inside the dispatch()
method. Later, we are going to move the list of routes to a separate config file.
<?php declare(strict_types=1);
namespace Invoice;
class Router
{
public function dispatch(Request $request): mixed
{
$path = $request->getPath();
$routes = [
'/' => function () {
echo 'Home Page';
},
'/invoices' => function () {
echo 'Invoices';
},
'/settings' => function () {
echo 'Settings';
}
];
return $routes[$path] ?? null;
}
}
Putting Everything Together
The App::run()
method is responsible for instantiating the Request
and Router
classes. The Request
object is passed as an argument of the Router::dispatch()
method.
<?php declare(strict_types=1);
namespace Invoice;
class App
{
public function run(): void
{
$router = new Router();
$request = new Request();
$handler = $router->dispatch($request);
if ($handler) {
$handler();
}
}
}
The dispatch() method returns a handler function that is later executed inside the run()
method. As a result, we render different content based on the request path information provided by the Request::getPath()
method.
Service Container
Both Request
and Router
classes may also be instantiated via the Service Container class that is responsible for managing dependencies. As for a simple PHP routing implementation, we aren’t going to add a service container. A separate post, however, will cover the service container topic.
And Finally…
You may watch a video tutorial with an additional explanation of the simple PHP router implementation. This video is a part of videos dedicated to the creation of the Invoice Management System.
All source code from this post can be found on GitHub.
Leave a Reply
You must be logged in to post a comment.