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

Il framework MVC Taste: ultimi accorgimenti

Le ultime porzioni di codice per completare il nostro framework MVC in PHP 5
Le ultime porzioni di codice per completare il nostro framework MVC in PHP 5
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.

Piano piano siamo giunti alla fine della serie dedicata allo studio e all'implementazione di un framework MVC in PHP 5. Abbiamo toccato in modo dettagliato i punti relativi al core, ai template e ai controller, lasciando alla teoria solamente i modelli e la persistenza che risultano concetti troppo complessi a livello implementativo per essere discussi in questa sede.

Con l'articolo di oggi si chiude per l'appunto la serie; ci occuperemo di riassumere i concetti trattati discutendo di come preparare Taste per essere praticamente utilizzato per la produzione di applicazioni di esempio sulla base di una versione corretta e bug free (ringrazio alcuni utenti di HTML.it per avermi segnalato gli errori) che potete scaricare come sempre dal link download in alto.

Preparare ed installare Taste

Molti di voi mi hanno chiesto dove posizionare i file che rappresentano i controller, i template ed i modelli in modo che risultino accessibili dalle funzionalità del framework. La configurazione standard del framework MVC (come impostata nel file static/debug.conf che potete trovare nell'archivio allegato scaricabile dal link download) indica al framework di ricercare i controller all'interno della cartella controllers, e i template all'interno della cartella views. Nel caso in cui i path indicati siano relativi, viene utilizzata come directory di base quella in cui è contenuta la root del framework taste.

I file che andremo a scrivere dovranno quindi essere installati in queste cartelle, e saranno accessibili utilizzando due sistemi differenti:

  • per accedere al template tramite le classi dedicate a questo compito ci basterà specificare il path relativo rispetto alla root dei template ove richiesto;
  • al controller invece (nonostante sia accessibile comunque utilizzando le normali regole di inclusione dei file) si accede normalmente dall'ExplicitRouter che ha pero' bisogno che il controller da eseguire sia specificato con una sintassi particolare: partendo dal path relativo del controller ci basta eliminare l'estensione .php, sostituire gli slash con dei punti ed aggiungere al risultato il nome della classe rappresentante il controller seguita dal nome del metodo da richiamare. Qualche esempio:
path/al/mio/controller.php (classe MioController, metodo azione_di_prova)
path.al.mio.controller.MioController.azione_di_prova

controller.php (classe MioController, metodo azione_di_prova)
controller.MioController.azione_di_prova

Dopo aver compreso questi concetti possiamo tranquillamente installare e configurare il framework. Proviamo a configurarlo in modo che:

  • posizioni i file statici ed il file di bootstrap all'interno del webserver, in modo che siano correttamente accessibili;
  • posizioni le cartelle dei controller, dei template, dei modelli ed il file di configurazione all'interno di una cartella con il nome dell'applicazione di esempio;
  • posizioni i file temporanei all'interno di una cartella separata;
  • posizioni il framework in un path accessibile globalmente;

Decomprimiamo l'intera cartella all'interno del filesystem in una locazione facilmente accessibile. Creiamo le cartelle che andranno ad ospitare i nostri dati (presuppongo di star lavorando su Linux):

shell> sudo mkdir /usr/local/taste
shell> sudo mkdir /usr/local/taste/framework
shell> sudo mkdir /usr/local/taste/applications
shell> sudo mkdir /usr/local/taste/applications/test_app
shell> sudo mkdir /usr/local/taste/tmp
shell> sudo mkdir /var/www/taste/webroot

Ora spostiamo i file contenuti all'interno del file compresso scaricato in modo che:

  • la cartella tmp risulti vuota;
  • la cartella test_app contenga a sua volta le cartelle views, models, controllers e static. L'ultima cartella conterrà anche il file di configurazione ed i due file statici html;
  •  la webroot contenga il file di bootstrap;
  • ed infine la cartella framework contenga tutti gli altri file;

Aggiorniamo correttamente i permessi:

shell> sudo chown -r www-data:www-data /usr/local/taste
shell> sudo chown -r www-data:www-data /var/www/taste
shell> sudo chmod -R 755 /usr/local/taste
shell> sudo chmod -R 777 /var/www/taste
shell> sudo chmod -R 777 /usr/local/taste/tmp

Affinché il framework si comporti correttamente abbiamo bisogno di apportare delle modifiche ai file seguenti:

framework/taste.php

require_once '/usr/local/taste/framework/taste/config/Configurable.php';

define('TASTE_DIR', "/usr/local/taste/framework/");

define('APPS_DIR', "/usr/local/taste/applications/");
define('CONFIGURATION_FILE', realpath("/usr/local/taste/applications/test_app/static/debug.conf"));
define('DEBUG_MODE', Configurable::queryConfiguration('Server', 'debug', 'off') == 'on');

webroot/bootstrap.php

<?php

ini_set('include_path', ini_get('include_path').':/usr/local/taste/framework:');

// il resto del file rimane invariato
// volendo è possibile impostare l'include_path dal file php.ini

applications/test_app/static/debug.conf

[Server]
debug = on
max_redirect = 10
dumpQueries = on
notFoundUri = notfound

[ExplicitRouter]
controllersDirs = /usr/local/taste/applications/test_app/controllers

[CachedRouter]
cacheDir = /usr/local/taste/tmp

[Database]
host = localhost
name = taste
username = root

[Template]
templateDirs = /usr/local/taste/applications/test_app/views/
nullAsBlank = on
invalidAsBlank = on

[CacheApplication]
cacheDir = /usr/local/taste/tmp
timeout = 0

Ora il framework dovrebbe essere correttamente installato e configurato e possiamo procedere con l'implementazione di un controller e di un template di esempio per assicurarci del corretto funzionamento.

L'applicazione di prova

Per implementare un'applicazione di prova dobbiamo necessariamente svolgere alcune operazioni operazioni:

  • in primo luogo è necessario creare una cartella all'interno di applications che rappresenti la root dei file della nostra applicazione (nel nostro caso sarà test_app);
  • in secondo luogo, se necessario, dobbiamo implementare la classe che servirà per usufruire della nostra applicazione. Nel nostro caso (e probabilmente anche in molti altri) possiamo fare affidamento ad MVCApplication;
  • successivamente dobbiamo modificare le opzioni di routing in modo che le richieste vengano interpretate correttamente dal router;
  • infine dobbiamo implementare i template ed i controller necessari;

Partiamo subito dal terzo punto tralasciando i primi due. La nostra applicazione si occuperà semplicemente di visualizzare una lista di dati contenuti in un file XML, filtrandoli ed ordinandoli eventualmente in base a determinati parametri. Le richieste che abbiamo la necessità di tracciare sono le seguenti (con il dollaro indico le parti che fungeranno da attributi alle nostre azioni):

userlist/list
userlist/sort/$FIELD

Com'è facilmente comprensibile il primo URL visualizza tutti i valori, il secondo li visualizza ordinati per un determinato campo. Eventualmente potremmo aggiungere altre opzioni più avanti. Il router dovrà quindi accettare i seguenti parametri:

return array(
    "^userlist/show/?$"  =>  "userlist.UserList.show",
    "^userlist/sort/([^/]+)/?$"  =>  "userlist.UserList.sort",
);

Che per comodità salveremo in /usr/local/taste/applications/test_app/route.php e successivamente includeremo all'interno del file di bootstrap. Il CachedRouter è stato disabilitato poiché in fase di debugging sarebbe necessario rimuovere il file di cache ogni volta che si modificano le opzioni di routing:

ini_set('include_path', ini_get('include_path').':/usr/local/taste/framework:');

define('APP_NAME', 'test_app');

require_once 'taste.php';
require_once 'taste/Server.php';
require_once 'taste/mvc/routing/ExplicitRouter.php';
//require_once 'taste/mvc/routing/CachedRouter.php';
require_once 'taste/applications/MVCApplication.php';
require_once 'taste/applications/CacheApplication.php';

$router = new ExplicitRouter(
    require_once(APPS_DIR."test_app/route.php")
);

//$router = new CachedRouter($router);

$server = new Server(
            new CacheApplication(
                new MVCApplication($router)));

$server->run();

Creiamo ora il controller che salveremo all'interno del file controllers/userlist.php:

<?php

require_once 'taste/Request.php';
require_once 'taste/mvc/Controller.php';
require_once 'taste/mvc/template/Template.php';

define("XML_CONTENT",
'<?xml version="1.0" encoding="UTF-8"?>
<userlist>
    <user>
        <name>Gabriele</name>
        <surname>Farina</surname>
    </user>
    <user>
        <name>Francesco</name>
        <surname>Caccavella</surname>
    </user>
    <user>
        <name>Cesare</name>
        <surname>Lamanna</surname>
    </user>
</userlist>
');

class UserList extends Controller
{
    private $sortField;
    
    public function show(Request $request)
    {
        $users = $this->loadUsers();
        return $this->render($users, 'nessuno');
    }
    
    public function sort(Request $request, $field)
    {
        $users = $this->loadUsers();
        $this->sortField = $field;
        
        usort($users, array($this, 'sortByField'));
        
        return $this->render($users, $field);
    }
    
    private function render($users, $field)
    {
        return Template::renderToResponse('userlist.tpl', array(
            'users' => $users,
            'field' => $field
            ));
    }
    
    private function sortByField($a, $b)
    {
        return strcmp($a[$this->sortField], $b[$this->sortField]);
    }
    
    private function loadUsers()
    {
        $file = 'userlist.xml';
        
        if(!file_exists($file))
        {
            $fp = fopen($file, 'w+');
            fwrite($fp, XML_CONTENT);
            fclose($fp);
        }
        
        $users = array();
        
        $doc = DOMDocument::load($file);
        
        foreach($doc->getElementsByTagName('user') as $node)
        {
            $users[] = array(
                'name' => $node->getElementsByTagName('name')->item(0)->childNodes->item(0)->nodeValue,
                'surname' => $node->getElementsByTagName('surname')->item(0)->childNodes->item(0)->nodeValue
            );
        }
        
        return $users;
    }
}

?>

Il controller è veramente semplice e si occupa semplicemente di salvare in un array associativo gli utenti, ordinandoli eventualmente in base al campo sortField nel caso in cui venga richiamata l'azione sort.

Infine l'ultimo tocco è creare il template, che salveremo in views/userlist.tpl:

<?xml version="1.0" encoding="utf-8" ?>
<html xmlns:tpl="http://taste.alittleb.it">
    <head>
        <title>User List</title>
    </head>
    <body>
        <h3>Utenti ordinati per: $field</h3>
        
        <ul>
            <li>
                <a href="bootstrap.php?url=userlist/show">Nessuno</a>
            </li>
            <li>
                <a href="bootstrap.php?url=userlist/sort/name">Nome</a>
            </li>
            <li>
                <a href="bootstrap.php?url=userlist/sort/surname">Cognome</a>
            </li>
        </ul>
        
        <div tpl:repeat="users,user">$user.surname $user.name</div>
        
    </body>
</html>

Per testare lo script ci basta puntare il browser al file di bootstrap, passando come parametro url=userlist/show.

Conclusione

Siamo giunti alla fine della serie. Spero possa essere interessata a qualcuno e abbia stimolato altri di voi nella ricerca di soluzioni sempre più complete per l'implementazione del pattern MVC applicato allo sviluppo web.

Ti consigliamo anche