Zend Framework : localiser un champ date

Principe de la transformation

Créer un champ date qui peut afficher la date au format local n'est pas si simple avec le Zend Framework. Voyons un peu comment procéder.

Manipulation des dates MySQL

Zend_Date ne supporte pas pour l'instant le format de date utilisé par MySQL car l'équipe qui développe le ZF ne souhaite pas alourdir encore un peu plus le code du composant avec des constantes adaptées à toutes les bases de données. Mais ce n'est pas un problème, puisqu'on a le code source. Il suffit d'étendre la classe Zend_Date :

<?php
class Wiip_Date extends Zend_Date
{
    const 
MYSQL_DATE 'yyyy-MM-dd';
    const 
MYSQL_DATETIME 'yyyy-MM-dd HH:mm:ss';
}
?>

Mise à jour du 4/12/09 : remplacé Y par y dans les codes de format de la date (http://wiip.fr/content/subtilit-de-zend-date).

Voilà, comme ça on dispose de deux constantes qui vont nous être utiles pour la suite. On peut en profiter pour ajouter d'autres méthodes utiles.

Transformer la date pour la stocker dans la base de données

Lorsqu'on récupére les données de notre formulaire pour les sauvegarder, on doit convertir la date du format local (JJ/MM/AA pour la France) au format de la base de données (AAAA-MM-JJ pour MySQL). Pour cela, on peut ajouter un filtre à notre élément de formulaire.

Filtre
<?php
class Wiip_Filter_LocalDateToMysql implements Zend_Filter_Interface
{
    public function 
filter($value)
    {
        if (
Zend_Date::isDate($valueZend_Date::DATE_SHORT)) {
            
// La valeur correspond bien à une date au format local court
            // On crée un objet date ...
            
$date = new Zend_Date($valueZend_Date::DATE_SHORT);
            
// ... et on le convertit au format MySQL
            
return $date->toString(Wiip_Date::MYSQL_DATE);
        }
        return 
$value;   
    }
}
?>

Pour utiliser ce filtre dans un élément de formulaire, il faut ajouter le chemin du composant aux chemins de recherche de plugin de l'élément :

<?php
// Pour tout le formulaire (à appeler dans la méthode init par exemple)
$this->addElementPrefixPath('Wiip_Filter''Wiip/Filter'Zend_Form_Element::FILTER);

// Pour un élément en particulier
$this->element->addPrefixPath('Wiip_Filter''Wiip/Filter'Zend_Form_Element::FILTER);
?>

Les filtres sont appliqués lors de l'appel à la méthode getValue de l'élément ou la méthode getValues du formulaire. Vous pouvez obtenir la valeur non filtrée en utilisant la méthode getUnfilteredValue de l'élément ou la méthode getUnfilteredValues du formulaire.

Valider la date

Avant d'écrire la date dans la base de données, il faut s'assurer qu'elle est bien valide car MySQL ne le fait pas. Le Zend Framework dispose d'un composant adapté à cette tâche : Zend_Validate_Date. Validateur

La valeur est filtrée avant de passer dans le validateur. Sur un élément non obligatoire (option required à false), les valeurs vides ne sont pas passées à la chaîne de validation.

Il suffit de lui passer en option le format de la date à valider :

<?php
$val 
= new Zend_Validate_Date(Wiip_Date::MYSQL_DATE);
?>

Charger la date dans le champ

Il nous reste une étape importante : charger la valeur lue dans la base de donnée dans notre élément de formulaire. Pour cela, on va écrire une aide de vue :

<?php
class Wiip_View_Helper_FormDate extends Zend_View_Helper_FormText
{
    public function 
formDate($name$value ''$attribs null)
    {
        if (!isset(
$attribs)) $attribs = array();

        (isset(
$attribs['class'])) ? $attribs['class'] .= ' date' $attribs['class'] = 'date';
        if (!isset(
$attribs['maxlength'])) $attribs['maxlength'] = strlen(Zend_Date::DATE_SHORT);
        if (!isset(
$attribs['size'])) $attribs['size'] = strlen(Zend_Date::DATE_SHORT);

        if (
Zend_Date::isDate($valueWiip_Date::MYSQL_DATE)) {
            
$date = new Zend_Date($valueWiip_Date::MYSQL_DATE);
            
$value $date->get(Zend_Date::DATE_SHORT);
        } elseif (
$value == '0000-00-00') {
            
$value '';
        }
        return 
parent::formText($name$value$attribs);
    }
}
?>
Aide de vue

L'aide de vue se charge de convertir la date MySQL au format local. Elle prédéfini également la largeur du champ (avec l'attribut size) et le nombre maximal de caractères autorisé ((avec l'attribut maxlength). On ajoute également une classe CSS date qui permet de personnaliser l'apparence du champ ou de lui appliquer une transformation avec Javascript.

Assembler le tout

Maintenant que tous les composants sont en place, on peut créer notre élément de formulaire :

<?php
class Wiip_Form_Element_Date extends Wiip_Form_Element_Text
{
    public 
$helper 'formDate';

    public function 
init()
    {
        
$this->addPrefixPath(
            
'Wiip_Filter',
            
'Wiip/Filter',
            
Zend_Form_Element::FILTER
        
);
        
$this->addFilter('LocalDateToMysql');
        
        
$val = new Zend_Validate_Date(Wiip_Date::MYSQL_DATE);
        
$this->addValidator($val);
    }
}
?>

Voilà, c'est fini. On peut utiliser la même méthode pour un champ permettant la saisie combiné d'une date et d'une heure. J'espère que cet exemple vous aura permis de mieux comprendre le fonctionnement des filtres, validateurs et aides de vue sur un élément de formulaire basé sur Zend_Form.

Commentaires

Ou places-tu ton filtre dans l'architecture de base Zend Framework ?

Dans le répertoire /library. Le chemin complet du fichier est /library/Wiip/Filter/LocalDateToMysql.php.

/library doit être dans include_path.

Ok merci.

Remarque, lorsque l'on passe une date courante au format mysql, celle ci ressort avec l'heure bloquée à 0. Pour conserver l'heure courante, il faut modifier le filtre et le remplacer par cette ligne :

" $date = new Zend_Date($value, Zend_Date::ISO_8601); "

Pour les datetime, j'ai un filtre adapté :


class Wiip_Filter_LocalDateTimeToMysql implements Zend_Filter_Interface
{
public function filter($value)
{
if (Zend_Date::isDate($value)) {
$date = new Zend_Date($value);
return $date->toString(Wiip_Date::MYSQL_DATETIME);
}
return $value;
}
}

j'ai vu que tu étends une classe(la classe Wiip_Form_Element_Tex) dont je vois pas la définition

Très juste (il y en a un au moins qui suit). En fait, c'est juste une surcharge de Zend_Form_Element_Text avec des decorators personnalisés.

Bonjour,

Je n'arrive pas à mettre ton exemple en place, peux tu m'expliquer comment tu définis le Wiip_View_Helper_FormDate ?

Merci

Pour que Wiip_View_Helper_FormDate fonctionne, il faut que le fichier FormDate.php soit placé dans /library/Wiip/View/Helper/, que l'espace de nom Wiip soit déclaré dans l'autoloader et que le préfixe soit enregistré au niveau du formulaire ou de l'élément comme je l'explique plus haut.

Si tu utilises Zend_Application, il faut ajouter l'espace de nom Wiip dans /application/configs/application.ini :


[..]

; Espaces de noms
autoloadernamespaces.0 = "Zend"
autoloadernamespaces.1 = "Wiip"

[..]

Super cool, grâce a votre article j'ai enfin compris comment en peut définir le Wiip_View_Helper_FormDate.

Amicalement

betclic

J'avais zappé l'ajout du changement de formatage de date (YYYY -> y)
Enfin la première fois que je suis passé il n'y étais pas. Du coup mon code ne fonctionnait que de façon aléatoire.
Tu devrais le mettre en plus gros je pense, ou changer l'exemple ;-)

Ajouter un commentaire