Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Il Framework MVC Taste: server e applicazioni

Come gestire le richieste e le risposte all'interno del nostro Framework Taste
Come gestire le richieste e le risposte all'interno del nostro Framework Taste
Link copiato negli appunti

Questo articolo fa parte di una serie dedicata alla programmazione di un framework MVC personalizzato in PHP. L'autore ha chiamato questo framework "Taste". Gli altri articoli della serie sono disponibili nella categoria Taste framework di php.html.it.

Nell'articolo precedente abbiamo discusso l'implementazione del registro globale e delle classi che si occupano di astrarre una richiesta inviata dal Web server ed una risposta generata dal sistema. Una volta che queste informazioni sono ricevute dal nostro script di bootstrap è necessario comunque che vi sia del codice che si occupa di associare un comportamento alle richieste in arrivo in modo da generare risposte corrette. In Taste il comportamento viene dato attraverso l'implementazione di un'applicazione che viene invocata da uno script centrale in modo che gestisca correttamente le chiamate. Lo script centrale è implementato nella classe Server, mentre le applicazioni sono delle sottoclassi della classe astratta Application.

Entrambe queste classi verranno descritte nel seguente articolo, e si fornirà una prima implementazione di testing del file di bootstrap in modo che sia possibile iniziare a testare il corretto funzionamento del framework.

Potete scaricare l'ultima versione del framework dal link donwload all'inizio dell'articolo.

Scheletro di un'applicazione

Iniziamo col discutere la classe Application (che potete trovare nel file taste/Application.php); l'implementazione viene fornita come classe astratta che andrà estesa quando si vorrà implementare un'applicazione che gestisca manualmente le richieste e le risposte.

<?php

require_once 'taste/Request.php';
require_once 'taste/config/Configurable.php';

abstract class Application extends Configurable
{
    private $base_app;
    
    public function __construct($base_app=null)
    {
        parent::__construct();
        
        $this->base_app = $base_app;
    }
    
    protected function runParent(Request $request)
    {
        if(!is_null($this->base_app))
            return $this->base_app->run($request);
    }
    
    abstract public function run(Request $request);
}

?>

Il costruttore delle classe accetta come parametro opzionale l'istanza di un'altra applicazione: questa possibilità è stata data in modo che sia possibile sviluppare applicazioni indipendenti che si occupino di gestire in modo trasparente richiesta e risposta senza sapere se la prima proviene direttamente dal server o da un'altra applicazione e se la seconda verrà stampata in output o gestita diversamente. In questo modo possiamo implementare applicazioni che fungano da middleware e che gestiscano comportamenti opzionali aggiuntivi indipendenti dall'effettiva gestione finale delle richieste (come ad esempio i caching).

Per rendere completo il comportamento viene fornita l'implementazione del metodo runParent che semplicemente esegue l'eventuale classe specificata come parent restituendone la risposta generata. Il metodo run viene lasciato come astratto e dovrà essere implementato dalle sottoclassi al fine di fornire un comportamento specifico.

Gestione esplicita delle richieste

Le richieste verranno instradate alle applicazioni attraverso una classe specifica chiamata Server (la cui implementazione è disponibile sul file taste/Server.php). Il server è il cuore del sistema e viene istanziato esplicitamente nel file di bootstrap in modo che gestisca le richieste e le risposte. Il server è una classe configurabile (attraverso la direttiva [Server]) e accetta come unico parametro di costruttore un'istanza di un'implementazione della classe Application.

Questa istanza verrà utilizzata come applicazione principale e richiamata automaticamente dal metodo pubblico run. Il metodo run si occupa di inizializzare la richiesta e richiamare il metodo run dell'applicazione; questo breve processo viene eseguito all'interno di un ciclo in modo che il server possa gestire in modo corretto eventuali azioni generate dall'applicazione. Un'azione è un'implementazione delle classe Action (che altro non è che una semplicissima eccezione) che però viene gestita internamente dal server. Le azioni implementate sono attualmente tre:

  • CONTROLLER_NOT_FOUND_ACTION: servirà più avanti quando implementeremo la classe MVCAction e indicherà il fatto che l'applicazione non ha trovato un controller corrispondente alla richiesta;
  • INTERNAL_REDIRECT_ACTION: indica un reindirizzamento interno, che viene gestito sfruttando la coda di redirect che abbiamo descritto nello scorso articolo ed eseguendo nuovamente l'azione sulla richiesta così trasformata. Il numero di redirect interni può essere limitato attraverso l'opzione di configurazione max_redirect: nel caso in cui il numero di reindirizzamenti risultasse troppo elevato, il server genererà un errore e terminerà l'esecuzione delle azioni;
  • HTTP_REDIRECT_ACTION: genera un semplice redirect HTTP utilizzando l'header Location;

Se l'applicazione non genera errori o eccezioni, il metodo run renderizza la risposta restituita ed esce silenziosamente. In caso invece l'applicazione invocata generi un'eccezione non gestita questa viene catturata e restituita in output: nel caso in cui il sistema si trovi in DEBUG_MODE, l'eccezione viene analizzata e viene restituito a video un semplice output HTML che permette di focalizzare facilmente l'errore e lo stack di chiamate che l'hanno generato; nel caso in cui invece il sistema di trovi in produzione, viene mostrata una pagina di errore statica e l'eccezione viene registrata attraverso il metodo reportException. Dato che ognuno ha un modo specifico per gestire gli errori in fase di produzione, ho preferito lasciare vuoto il metodo reportException.

Implementazione di prova del file di bootstrap

Ora che abbiamo discusso ed implementato gli ultimi mattoncini essenziali per il corretto funzionamento del core di Taste, possiamo passare ad implementare un file di bootstrap e delle applicazioni molto semplici per effettuare qualche test.

Per prima cosa implementiamo due semplici applicazioni.

TestApplication: restituisce in output l'URL richiesto dal web server preceduto da un semplice messaggio testuale

<?php

require_once 'taste/Application.php';
require_once 'taste/Response.php';

class TestApplication extends Application
{
    public function run(Request $request)
    {
        $response = new Response();
        $response->addContent("Chiamata gestita: ".$request->getPathInfo());
        
        return $response;
    }
}

?>

HTMLApplication: ingloba il risultato di un'applicazione figlia all'interno di una semplice pagina HTML, inserendo come titolo la data odierna

<?php

require_once 'taste/Application.php';
require_once 'taste/Response.php';

class HTMLApplication extends Application
{
    public function run(Request $request)
    {
        $response = $this->runParent($request);
        return new Response("
        <html>
            <head>
                <title>".date("d/m/Y")."</title>
            </head>
            <body>
                <h3>HTML APPLICATION</h3>
                <p>".$response->getContent()."</p>
            </body>
        </html>");
    }
}

?>

Queste applicazioni verranno istanziate e passate al server, che si occuperà di gestire le richieste attraverso il file di bootstrap:

<?php

require_once 'taste.php';
require_once 'taste/Server.php';

require_once 'HTMLApplication.php';
require_once 'TestApplication.php';

$server = new Server(new HTMLApplication(new TestApplication()));
$server->run();

?>

Dato che ci troviamo in debug mode, possiamo richiamare il file di bootstrap utilizzando il parametro url in modo da controllare che questo semplice flusso di operazioni venga eseguito in modo corretto. Per esempio, provando richiedere http://localhost/html.it/taste/taste_03/bootstrap.php?url=prova/indirizzo/nuovo (presupponendo che questo sia il path al file di bootstrap della vostra implementazione di Taste), otterremo il seguente output:

 <html>
        <head>
                <title>28/02/2007</title>
        </head>
        <body>
                <h3>HTML APPLICATION</h3>
                <p>Chiamata gestita: prova/indirizzo/nuovo</p>
        </body>
</html>

Conclusione

Pian piano cominciano a formarsi le basi per la costruzione del framework MVC; siamo ancora lontani dal completare Taste, ma con l'articolo di oggi è già possibile iniziare a sperimentare con l'implementazione di applicazioni differenti in modo da comprendere interamente il flusso di lavoro dei vari script. Nel prossimo articolo inizieremo a fornire l'implementazione dell'applicazione MVCApplication e del sistema di routing che potrà essere utilizzato per far corrispondere determinati controller a determinate richieste.

Ti consigliamo anche