mtweb

Le contrôleur

Anatomie d'un état : module/contrôleur/action 

Mtweb fonctionne sur un principe d'état. C'est à dire que chaque requête sur l'application va mettre cette dernière dans un état particulier, qui se traduira par l'exécution d'une action.

Chaque action est développée dans une méthode de classe, qui peut contenir plusieurs actions. Une classe qui définie des actions est un contrôleur. Les contrôleurs sont à leur tour organisés dans des dossiers, qui sont les modules de l'application.

Les modules se trouvent dans le répertoire :

app/controllers 

Chaque dossier dans ce répertoire est un module, dont les fichiers sont les contrôleurs, qui définissent chacun une classe comportant des méthodes qui sont les actions de l'application.

Par exemple le module config contient quatre contrôleurs :

Ce module config regroupe des contrôleurs utilisés pour les pages de configuration du site (gestion des rôles, des templates et des plugins).

Développer une nouvelle action 

Chaque requête sur mtweb DOIT avoir une action associée. Pour définir une nouvelle action vous pouvez l'ajouter dans un contrôleur qui existe déjà (en lui ajoutant une méthode de classe). Vous pouvez aussi ajouter un contrôleur, dans un nouveau fichier (en définissant une nouvelle classe de contrôleur), ou créer un module, dans un nouveau dossier du répertoire controllers, et y définir vos classes de contrôleurs avec leurs méthodes d'actions.

Dans l'exemple qui suit, on va créer un nouveau module, en se basant sur celui du Hello World.

Commençon donc par créer le dossier du module, qu'on va appeler hello :

app/controllers/hello

Et ajoutons dans ce dossier un fichier index.php avec ce code :

<?php

class mw_hello_index extends mw_controller{

function index(){

}

}

?>

Notre module s'appelle hello, son dossier porte son nom. Dans ce module, nous venons d'ajouter un contrôleur index. Ce contrôleur est donc défini, dans ce dossier, dans un fichier index.php. Ce fichier définie une classe. Cette classe est un contrôleur et doit suivre quelques conventions :

  • La classe s'appelle mw_<module>_<contrôleur>
  • Elle hérite de la classe mw_controller, qui est une classe fournie par mtweb et dont chaque contrôleur doit hériter.

Ce contrôleur propose une action index, et comporte donc une méthode index.

Executer une action avec un navigateur

Maintenant que nous avons définie notre nouvelle action, nous allons pouvoir y accéder via un navigateur, à l'URL :

index.php?e=hello 

note : l'action pour le moment ne fait rien et n'a pas non plus de vue associée, donc l'appel à cette URL ne vous donnera pas grand chose à part l'affichage du header et du footer. Mais ce simple affichage signifie déjà que l'action a bien été reconnue par l'application. Sinon un message d'erreur vous aurait informé que l'action demandée n'existe pas.

Dans l'URL ci-dessus, on utilise un paramètre GET de nom e. C'est ce paramètre qui permet de préciser l'état dans lequel on veut mettre l'application. Ici, on demande à l'application d'exécuter le module hello.

Module, contrôleur et action par défaut

Ce paramètre GET de nom e accepte plusieur syntaxes. La plus complète est la suivante :

index.php?e=<module>/<contrôleur>/<action>

Dans notre exemple, nous aurions pu utiliser l'URL :

index.php?e=hello/index/index

Pour préciser que nous souhaitons exécuter l'action index du contrôleur index dans le module hello. Si c'est bien cette action-là qui est exécutée lorque l'on ne précise que le module, c'est parce que mtweb utilise une convention de module, de contrôleur et d'action par défaut.

Si aucune action n'est précisée, c'est l'action index qui est exécutée. Si aucune action ni aucun contrôleur n'est précisé, c'est l'action index du contrôleur index qui est exécutée. On peut aussi ne passer aucun paramètre GET de nom e. Auquel cas c'est l'action index du contrôleur index du module index qui est exécutée.

Dans notre exemple, ces trois URL sont donc équivalentes :

index.php?e=hello/index/index
index.php?e=hello/index
index.php?e=hello

Associer une vue à une action

Pour le moment notre action ne génère aucun affichage. C'est parce qu'aucune vue ne lui est associée. Mtweb utilise un système de layout pour faire le lien entre les actions et les vues.

Commençons par créer un fichier d'affichage :

app/out/default/views/hello/index.php 

Avec ce code :

<h2>Hello !</h2>

Il nous faut maintenant indiquer à mtweb que pour notre action, c'est ce fichier qui doit être utilisé. Le module s'appelle hello, on va donc ajouter un fichier de layout pour ce module :

app/out/default/layouts/hello.xml

Avec ce code :

<?xml version="1.0" encoding="UTF-8"?>
<layout>

<hello page="index.php" content="views/hello/index.php" />

</layout>

Rechargez maintenant la page :

index.php?e=hello

Et vous devriez voir Hello ! apparaître entre le header et le footer.

Les fichiers de layout sont des fichiers XML qui acceptent aussi (comme le paramètre GET de nom e) différentes syntaxes avec des comportements par défaut.

Une syntaxe plus complète mais équivalente du fichier hello.xml serait la suivante :

<?xml version="1.0" encoding="UTF-8"?>
<layout>

<hello>
<index>
<index page="index.php" content="views/hello/index.php" />
</index>
</hello>

</layout>

Ici, notre module Hello ne contient qu'une action, mais un fichier de layout peut définir d'autres associations entre les actions et les vues d'un module.

→ plus d'infos sur les fichiers d'affichage

Transmettre des variables à une vue depuis une action

Dans une méthode d'action, c'est par l'intermédiaire de l'objet $env qu'on va pouvoir rendre des variables disponibles au moment de l'affichage, en utilisant la méthode set_out :

$env->set_out($key, $value) 

Pour continuer avec notre exemple, on pourrait passer un texte "Hello from action !" à la vue en utilisant cette méthode :

<?php

class mw_hello_index extends mw_controller{

function index(){
$env = $this->env();
$env->set_out("texte", "Hello from action !");
}

}

?>

L'objet $env possède un attribut out, qui n'est rien d'autre qu'un tableau associatif. La méthode set_out se contente d'ajouter une clé dans ce tableau (premier paramètre), à laquelle elle associe une valeur (second paramètre).

Au niveau d'un fichier d'affichage, c'est $this qui donne accès à l'objet $env. On va donc modifier notre vue :

app/out/default/views/hello/index.php

pour lui faire afficher la variable passée par l'action :

<h2><?php echo $this->out["texte"]; ?></h2>

note : mtweb fourni une fonction debug (qui fait basiquement un print_r dans une balise <pre>). Cette fonction permet par exemple de faire le point sur les variables disponibles dans un fichier d'affichage :

<?php debug($this->out); ?> 

Lire des données en base depuis une action

Une méthode de l'objet $env permet de récupérer un accès aux données :

$data = $env->data()

l'objet $data ainsi obtenu donne alors accès aux méthodes définies dans les modules de données.

→ plus de détails sur les modules de données

Dans l'exemple suivant, on va lire la liste des utilisateurs en base et la rendre disponible pour l'affichage :

<?php

class mw_hello_index extends mw_controller{

function index(){
$env = $this->env();
$data = $env->data();
$users = $data->users();
$env->set_out("users", $users);
}

}

?>

On peut commencer par faire un petit debug de ce que nous propose cette méthode users. Dans le fichier :

app/out/default/views/hello/index.php 

On remplace le contenu avec le code :

<?php debug($this->out); ?>

Et on recharge la page.

Cette méthode users retourne un tableau associatif avec une clé "list" qui contient elle-même un tableau associatif avec les informations des utilisateurs. On peut donc à nouveau modifier notre vue, cette fois avec le code :

<h2>Les utilisateurs :</h2>
<ul>
<?php foreach($this->out["users"]["list"] as $id_user => $user) : ?>
<li><?php echo $user["login"]; ?></li>
<?php endforeach; ?>
</ul>

Les erreurs, les messages et les redirections 

Quand on accéde à des informations dans une base de donnnées, ça commence à devenir intéressant de pouvoir prévoir un plantage. Si par exemple une lecture s'est mal passée, l'affichage de la vue prévue par le layout sera probablement buggé. Mieux vaut dans ce cas ne pas afficher la vue normale, et montrer à la place un message d'erreur.

C'est le rôle de la méthode erreur :

$env->erreur($message, $EXIT = false)

Cette méthode déclare une erreur. Si une erreur est déclarée, l'affichage normal de la page (via les informations du layout) est annulé. A la place, une page d'erreur apparaîtra avec le message précisée.

note : cette méthode N'ARRETE PAS le déroulement de l'action en cours. Si vous voulez vraiment stoper net, utilisez le deuxième paramètre avec TRUE. A ce moment-là, au lieu d'afficher une page d'erreur avec un header et un footer, seul le message sera affiché, suivi d'un exit Php.

De façon moins dramatique, on peut vouloir informer par exemple qu'une information fournie dans un formulaire est incorrecte, ou manquante.

C'est le rôle de la méthode message :

$env->message($message) 

Cette méthode enregistre un message qui sera affiché juste sous le header, en plus du contenu normal prévu par le layout.

Enfin, lorsque qu'une action s'est bien déroulée et que son exécution a entrainé des modifications dans la base, ça peut être une bonne idée d'enchainer sur une redirection automatique, avec une requête sans parametre POST par exemple (pour éviter qu'un rechargement de la page par l'internaute n'entraine une répétition de la modification dans les données).

Et c'est la méthode redirect qu'on va alors pouvoir utiliser :

$env->redirect($url, $message, $wait = 1)

Cette méthode effectue une redirection sur l'URL passée en premier paramètre. A la place de l'affichage prévu par le layout, c'est une page de redirection qui s'affichera, avec le message fourni dans le deuxième paramètre. Cette page s'affichera pendant 1 seconde avant que la redirection ne se fasse. Vous pouvez préciser une autre durée, en secondes, dans le troisième paramètre.

note : comme pour la fonction erreur, cette fonction N'ARRETE PAS le déroulement de l'action en cours. Elle se contente de déclarer une redirection, qui sera enclanchée une fois la méthode d'action terminée.

Un exemple de détection d'erreur

Un exemple un peu plus complet de notre fonction d'action, avec détection d'une erreur lors de la lecture de la base de données :

<?php

class mw_hello_index extends mw_controller{

function index(){
$env = $this->env();
$data = $env->data();
if(($users = $data->users()) === false){
$env->erreur("Impossible de lire la liste des utilisateurs");
return;
}
$env->set_out("users", $users);
}

}

?>

La méthode users sur l'objet $data retourne soit la liste des utilisateurs, soir FALSE si une erreur est survenue. En cas d'erreur, on utilise la méthode erreur sur l'objet $env, et le fichier d'affichage :

app/out/default/views/hello/index.php

n'est alors plus utilisé. A la place, une page d'erreur affichera le message :

Impossible de lire la liste des utilisateurs