m9/ PHP

Last update:   23-07-2021


We have decupled the URL from the code (with $map) v2.2 Stil, it's not flexible enough if we want something like: /hello/Fabian ! One important aspect of any website is the form of the URLs. To support this features, add Symfony Routing component as a dependency.
composer require symfony/routing
Let's write the new version of our framework
// public/front.php

require_once __DIR__.'/../vendor/autoload.php';

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing;

$request = Request::createFromGlobals();
$routes = include __DIR__.'/../src/app.php';

$context = new Routing\RequestContext();
$matcher = new Routing\Matcher\UrlMatcher($routes, $context);

try {
    extract($matcher->match($request->getPathInfo(), EXTR_SKIP));
    include sprintf(__DIR__.'/../src/pages/%s.phtml', $_route);
    $response = new Response(ob_get_clean());
} catch(Routing\Exception\ResourceNotFoundException $e) {
    $response = new Response('Not found', 404);
} catch (Exception $e) {
    $response = new Response('An error occured', 500);

... 15 lines
We separated the configuration (everything specific to our application in app.php) from the front controller (front.php).
// src/app.php

use Symfony\Component\Routing;

$routes = new Routing\RouteCollection();
$routes->add('hello', new Routing\Route(
    '/hello/{name}', ['name' => 'World']
$routes->add('bye', new Routing\Route('/bye'));

return $routes;
... 2 lines
    // Hello Fabian

    // Hello World

    // Not found
Framework v3.0 Fork v3.0c Details    (2/2)


There are a few new things in the code v3.0
- routes names are used for template names
- 500 errors are managed correctly
- attributes are extracted to keep template simple
- route configuration moved to its own file
Based on $routes information (RouteCollection instance), a UrlMatcher instance can match URL paths.
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;

$context = new RequestContext();
$matcher = new UrlMatcher($routes, $context);

$attributes = $matcher->match($request->getPathInfo());
The match() method takes a request path and returns an array of attributes. The matched route is automaticaly stored in _route attribute.
    // ['_route' => 'bye']

    // ['_route' => 'hello',
    // 'name' => 'Fabian']

    // ['_route' => 'hello',
    // 'name' => 'World']
... 2 lines
The request context is not strictly needed, but it is used in real-world applications to enforce method requirements and more.