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 :

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
class Wiip_Filter_LocalDateToMysql implements Zend_Filter_Interface
{
    public function filter($value)
    {
        if (Zend_Date::isDate($value, Zend_Date::DATE_SHORT)) {
            // La valeur correspond bien à une date au format local court
            // On crée un objet date ...
            $date = new Zend_Date($value, Zend_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 :

// 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 :

$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 :

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($value, Wiip_Date::MYSQL_DATE)) {
            $date = new Zend_Date($value, Wiip_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 :

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.

Portrait de Anonyme

Ou places-tu ton filtre dans

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

Portrait de Maxence Delannoy

Dans le répertoire /library.

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

/library doit être dans include_path.

Portrait de Anonyme

Ok merci. Remarque, lorsque

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); "

Portrait de Maxence Delannoy

Pour les datetime, j'ai un

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;
    }
}

Portrait de Anonyme

j'ai vu que tu étends une

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

Portrait de Maxence Delannoy

Très juste (il y en a un au

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.

Portrait de Anonyme

Bonjour, Je n'arrive pas à

Bonjour,

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

Merci

Portrait de Maxence Delannoy

Pour que

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"
 
[..]

Portrait de Anonyme

Super cool, grâce a votre

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

Amicalement

betclic

Poster un nouveau commentaire

Le contenu de ce champ ne sera pas montré publiquement. If you have a Gravatar account, used to display your avatar.
  • Les adresses de pages web et de messagerie électronique sont transformées en liens automatiquement.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Les lignes et les paragraphes vont à la ligne automatiquement.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. The supported tag styles are: <foo>, [foo].

Plus d'informations sur les options de formatage

CAPTCHA
La vérification ne tient pas compte des minuscules ou des majuscules.
Image CAPTCHA
Enter the characters shown in the image.