PROGRAMMING

m9/ PHP
REMEMBERS




Last update:   23-07-2021

Render Class

Our framework uses procedural code (function) for rendering templates v4.2 But $_controller can be any valid PHP callback. Lets convert our controller into a proper class.
 
// src/app.php

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

$routes = new Routing\RouteCollection();
$routes->add('isEven', new Routing\Route('/isEven/{no}', [
    'no' => null,
    '_controller' => [new CheckNumberController($request), 'index'],
]));

class CheckNumberController
{
    public function index ($request)
    {
        if ($this->isEven($request->attributes->get('no'))) {
            return new Response("Yes, the number is even!");
        }
        return new Response("No, the number is odd of null.");
    }

    public function isEven($no)
    {
        if (null === $no) return false;
        return $no % 2 == 0;
    }
}

return $routes;
... 18 lines
 

Kernel Resolver

The render controller is always instantiated, even if URL doesn't match the route. It will be bettter if the controllers are lazy-loaded. Lets use the HttpKernel
 
composer require symfony/http-kernel
! A controller resolver knows what controller to execute, based on the Request. It supports supports strings composed of a class name followed by two colons.
 
// public/front.php

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

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing;
use Symfony\Component\HttpKernel; // Look Here

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

$context = new Routing\RequestContext();
$context->fromRequest($request);
$matcher = new Routing\Matcher\UrlMatcher($routes, $context);

// Look Here
$controllerResolver = new HttpKernel\Controller\ControllerResolver();
$argumentResolver = new HttpKernel\Controller\ArgumentResolver();

try {
    $request->attributes->add(
        $matcher->match($request->getPathInfo())
    );

    // Look Here
    $controller = $controllerResolver->getController($request);
    $arguments = $argumentResolver->getArguments($request, $controller);

    $response = call_user_func_array(
        $controller, $arguments
    );
} catch(Routing\Exception\ResourceNotFoundException $e) {
    $response = new Response('Not found', 404);
} catch (Exception $e) {
    $response = new Response('An error occured', 500);
}

$response->send();
... 24 lines
 
! Argument resolver getArguments() inspects the controller signature. It determines which arguments to pass using PHP reflexion.
 
// src/app.php

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

$routes = new Routing\RouteCollection();
$routes->add('isEven', new Routing\Route('/isEven/{no}', [
    'no' => null,
    '_controller' => 'CheckNumberController::index', // Look Here
]));

class CheckNumberController
{
    public function index ($no)   // Look Here
    {
        if ($this->isEven($no)) {
            return new Response("Yes, the number is even!");
        }
        return new Response("No, the number is odd of null.");
    }

    public function isEven($no)
    {
        if (null === $no) return false;
        return $no % 2 == 0;
    }
}

return $routes;
... 18 lines
 
 
http://tests.local/php/framework/public/isEven/2 
    // Yes, the number is even!

http://tests.local/php/framework/public/isEven/23 
    // No, the number is odd of null.
Framework v5.0
Questions    
SoC

        A B C D E F
🔔
1/2