Le framework SALT permet de simplifier l'affichage des données provenants des
objets mappés
Le formatage des objets fait intervenir plusieurs classes :
- ViewControl est une classe qui va définir le comportement global attendu de la page et qui contrôle comment les
champs sont affichés.
- Base est la classe mère des objets mappés. Elle définit des accesseurs supplémentaires aux propriétés de
l'objet :
VIEW,
FORM,
SQL et
COLUMN
.
- AbstractConverter / DAOConverter / MonObjetDAOConverter sont les classes qui sont appelées par les méthodes
VIEW, FORM, SQL et COLUMN pour réellement formater les données
- FormHelper est une classe appelée par
FORM pour générer des balises de formulaires si nécessaire.
Elle sera détaillée dans la section suivante qui lui est dédiée.
Tout d'abord il faut définir le comportement global que l'on souhaite avec
ViewControl
Ce format se déclare en général
une fois en haut de la page et il reste en place pour la page tant qu'on n'en
appelle pas un autre.
Il existe 3 formats dans
ViewControl (correspondant à 3 méthodes de même nom dans les classes
DAOConverter) :
- ViewControl::text() Correspond à un formatage des valeurs pour affichage, mais sans aucun échappement HTML.
Par exemple pour envoyer un mail au format texte ou encore pour générer un PDF; si une valeur contient le caractère
">", il sera renvoyé tel quel, et non comme ">" comme il le serait s'il était échappé pour un affichage HTML.
- ViewControl::show() (format par défault) Identique au format text() mais les valeurs seront
échappées pour un affichage HTML.
- ViewControl::edit() Correspond à une page permettant de modifier des valeurs de l'objet. En interne, l'affichage
d'une valeur se fera avec la classe
FormHelper
Puis on a la méthode d'affichage locale de chaque champ.
Cette méthode est à écrire
à chaque fois, pour chaque champ à afficher.
On peut choisir entre 2 méthodes :
- $monObjet->VIEW->champ: Affiche la valeur du champ
- $monObjet->FORM->champ: Affiche une balise HTML permettant de modifier le champ (input, select, etc...)
Lors de l'affichage d'une valeur, les méthodes de la classe fille de DAOConverter suivantes seront appelées en fonction de
ViewControl
et de
VIEW/FORM.
| | Méthode DAOConverter |
| ViewControl | VIEW | FORM |
| text() | text($value) (A) | text($value) (B) |
| show() | show(text($value))) (C) | show(text($value)) (D) |
| edit() | show(text($value)) (E) | edit(show(text($value))) (F) |
Quelques cas d'utilisation permettant de comprendre comment lire le tableau :
- (B) ViewControl::text() positionné en haut de la page, et $monObjet->FORM->champ : Le ViewControl a la priorité et on
ne peux pas afficher de formulaire pour une sortie "texte", donc on appliquera juste la fonction de formatage
text()
sur le champ
- (D) ViewControl::show() positionné en haut de la page, et $monObjet->FORM->champ : Le ViewControl a la priorité et on
ignore donc le fait que le champ puisse être affiché comme un formulaire : on va appliquer la fonction de formatage
text()
sur le champ puis la fonction de formatage show()
- (E) ViewControl::edit() positionné en haut de la page, et $monObjet->VIEW->champ : Le ViewControl a la priorité mais
le champ ne peux pas être affiché comme un formulaire, donc on l'affiche comme une valeur en appliquant la fonction
de formatage
text() sur le champ puis la fonction de formatage show()
- (F) ViewControl::edit() positionné en haut de la page, et $monObjet->FORM->champ : Le ViewControl nous indique
d'afficher un formulaire et le champ peut être affiché comme tel. On applique donc le formatage
edit() qui va
construire la balise HTML adéquate (select, input, textarea, etc...) et qui appelera le formatage show() sur le
formatage text() pour afficher la ou les valeurs du champ dans le formulaire.
Avec ce mécanisme qui peut paraitre un peu complexe, on peut plus facilement factoriser les pages d'affichage et de modification
des données :
<?php
// ------- object_edit.php : page de modification
ViewControl::edit();
include '_display.php';
// ------- object_show.php : page d'affichage
ViewControl::show();
include '_display.php';
// ------- _display.php : page interne affichant les champs
echo $monObjet->VIEW->champEnReadOnly; // La valeur du champ sera affichée, meme avec ViewControl::edit();
echo $monObjet->FORM->champ; // Le formulaire du champ ne sera affichée que si ViewControl::edit(),
// sinon ce sera sa valeur, comme si on avait utilisé $monObjet->VIEW->champ
Les méthodes de formatages se trouvent dans la classe
DAOConverter.
On décrit ci dessous le comportement par défaut des 3 méthodes de formatage suivantes :
text(),
show(),
edit()
text()
- Si le format est
FormHelper::RAW on renverra la valeur brute du champ
- Si le champ à afficher est défini dans la méthode
metadata() avec une liste de valeurs et que la valeur du champ
appartient à cette liste, on renverra la valeur textuelle correspondante.
- Si le champ est déclaré au format DATE, il sera formaté avec le format d'affichage défini
- Si le champ est déclaré au format BOOLEAN on renverra 1 (TRUE) ou 0 (FALSE)
- Dans tout les autres cas on renverra la valeur brute du champ
<?php
class DisplayTest extends Base {
const STATUS_NEW = 0;
const STATUS_OLD = 1;
function metadata() {
parent::MODEL()
->registerFields(
Field::newNumber('status', 'Status', FALSE, self::STATUS_NEW, array(
self::STATUS_NEW => 'Nouveau',
self::STATUS_OLD => 'Ancien',
)),
Field::newDate('date', 'Date', SqlDateFormat::TIMESTAMP, 'd/m/Y'),
Field::newBoolean('response', 'Réponse')
);
}
}
$dt = new DisplayTest();
$dt->status = DisplayTest::STATUS_OLD;
$dt->date = 499134060;
$dt->response = TRUE;
ViewControl::text();
echo 'Object values : <br/>';
var_dump($dt->status); echo '<br/>'; // affiche int(1)
var_dump($dt->date); echo '<br/>'; // affiche int(499134060)
var_dump($dt->response); echo '<br/>'; // affiche bool(true)
echo 'Object values with text format : <br/>';
var_dump($dt->VIEW->status); echo '<br/>'; // affiche string "Ancien"
var_dump($dt->VIEW->date); echo '<br/>'; // affiche string "26/10/1985"
var_dump($dt->VIEW->response); echo '<br/>'; // affiche int(1)
La méthode show() se contente d'échapper le retour de la fonction text() pour un affichage HTML.
<?php
$city = new City();
$city->city_name='Ville <b>moderne !</b>';
ViewControl::text();
echo $city->VIEW->city_name.'<br/>'; // affiche "Ville moderne !" avec "moderne !" en gras, les balises <b> n'étant pas échappées
ViewControl::show();
echo $city->VIEW->city_name.'<br/>'; // affiche "Ville <b>moderne !</b>"
- Si le champ est déclaré avec une liste de valeurs, une balise SELECT sera générée avec les valeurs textuelles des valeurs
dans les balises OPTIONS (valeurs affichées en appelant la méthode show() sur chacune)
- Si le champ est de type BOOLEAN non NULL, on affichera une case à cocher
- Si le champ est de type BOOLEAN nullable, on affichera une liste déroulante avec les options "" (vide, correspond à
NULL), "Oui", "Non"
- Si le champ est de type DATE, on ajoutera une fonction d'initialisation du champ comme un datepicker JQuery après
la déclaration d'un INPUT de type text
- Dans tout les autres cas on génère un INPUT de type text
A noter que si la valeur du champ est présente dans $_GET ou $_POST (en fonction du type du formulaire), elle sera prioritaire
par rapport à la valeur de l'objet et sera utilisée à la place, y compris pour cocher ou non une case à cocher ou pour sélectionner
un élément dans une liste déroulante (SELECT).
COLUMN / column()
La méthode
MonObjet::COLUMN()->column permet d'afficher un texte représentant un champ.
Cela se traduit par l'appel de la méthode
column() sur le DAOConverter.
Par défaut, la méthode column() renvoi le texte associé au champ, c'est-à-dire le 2ème paramètre des méthodes
Field::newXXX() utilisées dans la méthode
metadata() pour décrire l'objet mappé.
<?php
class DisplayTest extends Base {
function metadata() {
parent::MODEL()->registerFields(
// Définition du texte correspondant au champ
Field::newDate('date', 'Date de modification', SqlDateFormat::TIMESTAMP, 'd/m/Y'),
);
}
}
// Plusieurs possibilités existent pour l'appel à COLUMN, qui affichera "Date de modification" :
echo DisplayTest::COLUMN()->date; // Utilisation de la méthode statique, mais on doit spécifier les parenthèses
echo DisplayTest::singleton()->COLUMN->date; // Utilisation de l'accesseur, les parenthèses sont facultatives mais on doit réaliser l'appel sur une instance de l'objet
On peut également passer un 2ème paramètre $format :
DisplayTest::COLUMN($format)->$fieldName qui sera propagé
jusqu'à la méthode formatage qu'on peut surcharger :
public function column(Base $object, Field $field, $value, $format, $params)
SQL / sql()
La méthode
MonObjet->SQL->column permet de convertir le champ pour une utilisation dans une requête SQL avec l'API SQL.
Cela se traduit par l'appel de la méthode
sql() sur le DAOConverter.
Par défaut les seules conversions effectuées sont :
- Les booléens sont convertis en 0 (FALSE) et 1 (TRUE)
- Les dates sont converties dans le format défini
Un exemple est disponible dans l'
API SQL.
Il est également possible d'appeler la méthode
MonObjet->FORM->column = ... pour modifier la valeur d'un objet à partir d'une valeur provenant d'un formulaire.
Cela se traduit par l'appel de la méthode
setterInput() sur le DAOConverter.
Par défaut les conversions effectuées sont :
- Si le champ est déclaré nullable et que la valeur est une chaine vide, la valeur est convertie en NULL
- Si la valeur vaut
Field::EMPTY_STRING la valeur est convertie en chaine vide.
- Si le champ est un NUMBER, la valeur est convertie en entier ou une exception est levée si la valeur n'est pas un entier
- Si le champ est un BOOLEAN, la valeur est convertie en booléen, avec la valeur TRUE si la valeur vaut 1, "1", ou "on"
- Si le champ est une DATE, la valeur est convertie en timestamp avec le format défini de la date ou une exception est levée si la date est invalide
Il est conseillé d'utiliser cette méthode lorsqu'on modifie une valeur depuis un formulaire,
cela permet d'éviter de faire des conversions dans la page du formulaire.
Par exemple, pour un champ date :
<?php
if ($Input->P->ISSET->submit) {
$monObjet->date = $Input->P->RAW->date; // ne fonctionne pas : la valeur saisie est au format DD/MM/YYYY, alors que la valeur
// stockée dans l'objet est au format TIMESTAMP
$monObjet->FORM->date = $Input->P->RAW->date; // fonctionne correctement, le champ sera converti en TIMESTAMP avant d'être affecté à l'objet
$monObjet->FORM('Y/m/d')->date2= $Input->P->RAW->date2; // Si on utilise un format spécifique, il suffit d'utiliser le même format
// et la conversion en tiendra compte
}
?>
...
Date : <?= $monObjet->FORM->date; // affichage de l'input date ?>
Date2 : <?= $monObjet->FORM('Y/m/d')->date2; // affichage d'un input date avec un format spécifique ?>
chargement d'objet / setterDB()
Lorsqu'on charge un objet depuis la base de données, chaque valeur est convertie avec un appel à la méthode
setterDB.
Par défaut, on réalise les opérations suivantes :
- Si la valeur est NULL, on ne fait pas de conversions
- Si le champ est un nombre et que le champ n'est pas un nombre, on lève une exception
- Si le champ est un booléen, la valeur vaut TRUE si elle vaut 1, "1" ou "on"
- Si le champ est une date, la valeur est convertie en timestamp, ou une exception est levée si la date est invalide.
set / setter()
Lorsqu'on modifie la valeur d'un champ directement, chaque valeur est convertie avec un appel à la méthode
setter.
Par défaut on ne réalise aucune conversion.
On peut passer un paramètre à la méthode VIEW, FORM, SQL ou COLUMN afin de surcharger le format d'affichage.
Ce qu'on appelle
format d'affichage ici est une
nouvelle notion qui n'a rien à voir avec text/show/edit ou form/view.
Le format d'affichage est un paramètre qui est propagé jusqu'aux méthodes de formatage et qui peut influencer leur comportement.
Il existe 2 types de formats d'affichage qui influencent le formatage par défaut présenté dans les méthodes précédentes:
- Le format
FormHelper::RAW qui va modifier le comportement de la méthode text() en annulant son formatage.
Elle renverra donc la valeur sans modification, quelque que soit son type
- Si le champ est de type DATE, tout format passé à VIEW ou FORM sera utilisé à la place du format déclaré dans le champ.
Cela permet de surcharger localement le format d'affichage d'une date
<?php
class DisplayTest extends Base {
const STATUS_NEW = 0;
const STATUS_OLD = 1;
function metadata() {
parent::MODEL()
->registerFields(
Field::newNumber('status', 'Status', FALSE, self::STATUS_NEW, array(
self::STATUS_NEW => 'Nouveau',
self::STATUS_OLD => 'Ancien',
)),
Field::newDate('date', 'Date', SqlDateFormat::TIMESTAMP, 'd/m/Y'),
Field::newText('text', 'Texte')
);
}
}
ViewControl::show();
$dt = new DisplayTest();
$dt->status = DisplayTest::STATUS_OLD;
$dt->text = 'OLD<NEW';
$dt->date = 499134060;
echo $dt->VIEW->date.'<br/>'; // affiche "26/10/1985"
echo $dt->VIEW('d/m/Y H:i:s')->date.'<br/>'; // affiche "26/10/1985 01:21:00"
echo $dt->VIEW->status.'<br/>'; // affiche "Ancien"
echo $dt->VIEW(FormHelper::RAW)->status.'<br/>'; // affiche 1, ce qui a l'air équivalent à $dt->status
echo $dt->VIEW->text.'<br/>'; // affiche "OLD<NEW"
echo $dt->VIEW(FormHelper::RAW)->text.'<br/>'; // affiche "OLD<NEW" ... mais n'est PAS équivalent à $dt->text car le
// texte est quand même échappé pour un affichage HTML !
echo $dt->text.'<br/>'; // affiche OLD... et casse le reste de la page en affichant une balise HTML "<NEW",
// le champ n'étant pas échappé pour un affichage HTML
Surcharge des méthodes
Il est possible de sucharger les méthodes de la classe
DAOConverter pour chaque objet mappé en définissant une classe
MonObjetDAOConverter pour l'objet
MonObjet
MonObjetDAOConverter doit être une classe fille de
DAOConverter.
<?php
class DisplayTest extends Base {
function metadata() {
parent::MODEL()->registerFields(
Field::newNumber('id', 'ID', FALSE),
Field::newText('text', 'Texte')
);
}
}
// Définition du DAOConverter
class DisplayTestDAOConverter extends DAOConverter {
public function text(Base $object, Field $field, $value, $format, $params) {
// On peut redéfinir completement une méthode, ici on entoure chaque valeur de parenthèses
return '('.parent::text($object, $field, $value, $format, $params).')';
}
public function show(Base $object, Field $field, $value, $format, $params) {
$In = In::getInstance();
switch($field->name) {
case 'id':
// on peut aussi ne modifier l'affichage que d'un champ spécifique en filtrant par $field->name
// Ici va afficher un lien vers la page de consultation d'un ID plutot que d'afficher un simple ID
return '<a href="'.WEB_RELATIVE.'examples/display/answer.php?id='.$In->URL($value).'">'.
parent::show($object, $field, $value, $format, $params).'</a>';
break;
}
return parent::show($object, $field, $value, $format), $params;
}
}
$dt = new DisplayTest();
$dt->id = 42;
$dt->text = 'OLD<NEW';
echo $dt->VIEW->text.'<br/>'; // affiche "(OLD<NEW)"
echo $dt->VIEW->id; // affiche un lien vers "examples/display/answer.php?id=42" avec pour texte "(42)"
Il est important de comprendre la différence entre text() et show() :
- text() renvoi une représentation textuelle de la valeur, sans aucune balise HTML
- show() renvoi une représentation complexe de la valeur, avec un échappement HTML
Dans l'exemple précédent, il aurait été impossible de générer un lien HTML dans la méthode
text() car le retour
de la méthode text() sera échappé en HTML dans show(). Il se serait donc affiché le code du lien et non un lien fonctionnel.

Il est fortement recommandé d'appeler les méthodes parentes
parent::text(), parent::show(), parent::edit() lors de leur
surcharge afin de conserver le formatage par défaut.

En cas de surcharge de
parent::show et parent::edit le retour
DOIT être une chaîne où toutes les variables
sont filtrées et échappées pour un affichage HTML. La classe
In est faite pour ca
Un autre exemple permettant d'introduire un 2ème niveau de condition :
Imaginons qu'on souhaite afficher un lien vers un ID, mais qu'on veux pouvoir afficher aussi l'ID tout seul sans lien :
On va utiliser le paramètre
$format qui est propagé jusqu'aux méthodes de formatage :
<?php
...
public function show(Base $object, Field $field, $value, $format, $params) {
$In = In::getInstance();
switch($field->name) {
case 'id':
if ($format === 'link') {
return '<a href="'.WEB_RELATIVE.'examples/display/answer.php?id='.$In->URL($value).'">'.
parent::show($object, $field, $value, $format, $params).'</a>';
}
break;
}
return parent::show($object, $field, $value, $format, $params);
}
...
echo $dt->VIEW->id; // affiche l'ID sans lien
echo $dt->VIEW('link')->id; // affiche un lien vers "examples/display/answer.php?id=42" avec pour texte "(42)"
Enfin, si on souhaite accéder à plusieurs champs pour construire l'affichage d'un champ, c'est possible puisque chaque méthode
à en paramètre l'objet
Base sur lequel on a appliqué la méthode de formatage.
Appels internes
Le schéma ci-dessous présente les interactions de la classe DAOConverter avec les autres classes.