Nel precedente capitolo abbiamo accennato al routing nel pattern MVC mostrando il file .htaccess
che stiamo usando. Abbiamo visto come tutte le richieste che non puntino a file e directory esistenti vengano reindirizzate sul file index.php
. In questo capitolo ne vedremo i dettagli.
Sostanzialmente si tratta di correlare le parti di un URL di una richiesta ad un controller specifico e ad un suo metodo pubblico che può a volte accettare argomenti.
Quindi dato un URL come:
/pages/view/8
l’URL va scomposto esplodendone le parti separate dal carattere /
che corrisponderanno al controller, al suo metodo e all’argomento del metodo partendo da sinistra. Avremo:
class Pages {
public function view($id) {
}
}
Notiamo già un problema: il nome della classe è Pages
mentre il frammento dell’URL è pages
in minuscolo. Inoltre view
potrebbe essere scritto come view-page
e il metodo corrispondente essere quindi viewPage
in notazione camel-case. Come risolvere queste discrepanze?
Per far questo dobbiamo creare una classe Dispatcher
che effettui il parsing dell’URL delle richieste, carichi il controller corrispondente e risolva le discrepanze a cui accennavamo.
La classe è la seguente:
class Dispatcher {
protected $params;
protected $controller;
public function __construct($controller) {
$this->controller = $controller;
$this->params = $this->parse($_SERVER['REQUEST_URI']);
}
public function handle() {
$action = $this->params['method'];
$args = $this->params['args'];
if(method_exists($this->controller, $action)) {
if(!is_null($args)) {
$this->controller->$action($args);
} else {
$this->controller->$action();
}
} else {
Site::error();
}
}
protected function parse($path) {
if($path == '/') {
return [
'method' => 'index',
'args' => null
];
} else {
$parts = array_values(array_filter(explode('/', $this->removeQueryStringVariables($path))));
$method = $this->convertToCamelCase($parts[0]);
$args = array_slice($parts, 1);
return [
'method' => $method,
'args' => (count($args) > 0 ) ? $args : null
];
}
}
protected function convertToStudlyCaps($string) {
return str_replace(' ', '', ucwords(str_replace('-', ' ', $string)));
}
protected function convertToCamelCase($string) {
return lcfirst($this->convertToStudlyCaps($string));
}
protected function removeQueryStringVariables($url) {
$parts = explode('?', $url);
return $parts[0];
}
}
I metodi fondamentali sono parse()
e handle()
. Il primo accetta come argomento l’URL della richiesta HTTP. Se corrisponde a /
siamo nella home del sito. Altrimenti il percorso viene esploso e vengono subito rimosse le eventuali variabili aggiunte da una query string GET. Quindi viene estratto il nome del metodo convertito in notazione camel-case e i suoi eventuali argomenti.
L’output restituito è un array associativo in cui la voce method
corrisponde al metodo del controller e args
è un array lineare di argomenti del metodo.
Il metodo handle()
utilizza parse()
per ottenere il nome del metodo e i suoi parametri. Se il metodo esiste nel controller, viene invocato con i suoi argomenti (o senza argomenti se non ve ne sono).
Dato che il nostro e-commerce è molto semplice, usiamo un solo controller, ossia la classe Shop
che abbiamo già visto a titolo di esempio in precedenza.
Se avete più controller, semplicemente il primo elemento dell’array delle parti del path diventa il nome del vostro controller che poi potete includere e istanziare prima di invocarne il metodo.
Conclusione
In questo capitolo abbiamo visto il funzionamento del routing nel pattern MVC. Nel prossimo capitolo vedremo il pattern MVC in relazione con i namespace e l’autoloading in PHP.