Consultez la FAQ sur le ZF avant de poster une question
Vous n'êtes pas identifié.
Bonjour,
J'essaie de plus en plus d'utiliser les validateurs de Zend, notamment pour les formulaires.
Je suis tombé sur un cas où il me fallait un validateur qui vérifie la présence de plusieurs valeurs dans la table.
N'ayant pas réussit à le faire avec les validateurs standard, j'ai adapté Zend_Validate_Db_NoRecordExists.
Je pense que cela peut être utile à d'autres... donc le voici :
<?php /** * Zend Framework Addon * * Addon to be used in the 'My' Library, performs a DataBase test * on multiple fields. Used with Zend_From return the Error message * if all values match. * As to be integrated on the first element of the array. * * @category Zend * @package My_Validate_Db * */ require_once 'Zend/Validate/Abstract.php'; class My_Validate_Db_MultiFields extends Zend_Validate_Abstract { /** * Error constants */ const ERROR_RECORD_FOUND = 'recordFound'; /** * @var array Message templates */ protected $_messageTemplates = array( self::ERROR_RECORD_FOUND => "A record matching '%value%' was found", ); /** * @var string */ protected $_table = ''; /** * @var array */ protected $_fields = array(); /** * @var string */ protected $_subformExt = false; /** * Database adapter to use. If null isValid() will use Zend_Db::getInstance instead * * @var unknown_type */ protected $_adapter = null; /** * Confirms a record exists in a table on mutiple field. * Fields array : * array( * 'field_1', * 'field_2',...) * * @param TableName(string) $table * @param FieldList(array) $fields * @return void */ public function __construct($table, $fields) { $options['table'] = $table; $options['fields'] = $fields; if (!array_key_exists('table', $options) && !array_key_exists('schema', $options)) { require_once 'Zend/Validate/Exception.php'; throw new Zend_Validate_Exception('Table or Schema option missing!'); } if (!array_key_exists('fields', $options)) { require_once 'Zend/Validate/Exception.php'; throw new Zend_Validate_Exception('Field option missing!'); } if (!is_array($options['fields'])) { require_once 'Zend/Validate/Exception.php'; throw new Zend_Validate_Exception('Field option must be an array!'); } $this->setFields($options['fields']); $this->_table = (string) $options['table']; } public function setFields($options) { foreach($options as $v){ $this->_fields[] = (string) $v; } } /** * Run query and returns matches, or null if no matches are found. * * @param Array $values * @return Array when matches are found. */ protected function _query($values) { /** * Check for an adapter being defined. if not, fetch the default adapter. */ if ($this->_adapter === null) { $this->_adapter = Zend_Db_Table_Abstract::getDefaultAdapter(); if (null === $this->_adapter) { require_once 'Zend/Validate/Exception.php'; throw new Zend_Validate_Exception('No database adapter present'); } } /** * Build select object */ $select = new Zend_Db_Select($this->_adapter); $select->from($this->_table, $this->_fields); foreach ($values as $k => $v) $select->where($this->_adapter->quoteIdentifier($k).' = ?', $v); $select->limit(1); /** * Run query */ $result = $this->_adapter->fetchRow($select); return $result; } public function isValid($value, $context = null) { $valid = true; /** * Set (array)$values to be sent to query */ $values = array($this->_fields[0] => $value); for ($i=1;$i < count($this->_fields);$i++) $values[$this->_fields[$i]] = $context[$this->_fields[$i]]; /** * Put all fields nam into %value% */ $this->_setValue(implode(', ', $values)); $result = $this->_query($values); if ($result) { $valid = false; $this->_error(self::ERROR_RECORD_FOUND); } return $valid; } }
localisation : library/My/Validate/Db/MultiFields.php
Utilisation:
Pour unformulaire
$nom = new Zend_Form_Element_Text('nom'); $nom->setLabel('Nom') ->addValidator( new My_Validate_Db_MultiFields('users', array('nom','prenom'))) ->setRequired(); $prenom = new Zend_Form_Element_Text('prenom'); $prenom->setLabel('Prénom') ->setRequired();
ou librement
$validator = new My_Validate_Db_MultiFields('foo',array('ch1','ch2','ch3')); if($validator->isValid($valueCh1, array($valueCh2, $valueCh3))) /** * N'est pas présent dans la table */ }else{ /** * Est déjà enregistré */ }
Revoie le message d'erreur dans le cas où le "couple" nom/prenom est présent dans la base.
Peut être rapidement adapté pour la vérification de la répétition de mot de passe et, bien sûr amélioré.
Dernière modification par Dede (22-08-2010 12:16:16)
Hors ligne
Merci pour ce code qui, après quelques modifications (pour l'adapter à mon code), s'avère fonctionner !
Hors ligne
De rien, c'est le principe
Hors ligne
Je suis d'accord mais bon merci ça coute rien, et puis ça m'a fait gagner du temps ^^'
Hors ligne
Bonjour,
Cette fois j'ai une question sur mon propre validateur...
Lorsque je le déclare je procède de la manière suivante :
$element = Zend_Form_Element_text('foo') $element->setLabel('Foo') ->addValidator(new My_Validate_Db_MultiFields('ma_table', array('champ1', 'champ2')));
Mais pour l'update il bloque puisque, effectivement, le "couple" champ1 & champ2 est déjà présent...
Alors j'aimerais le déclarer de cette façon pour pouvoir utiliser la méthode removeValidator('Db_MultiFields'):
... ->addValidator('Db_MultiFields', false, array('ma_table', array('champ1', 'champ2'))); ...
Mais cela ne fonctionne pas car il ne trouve pas le validateur perso.
Est il possible de le déclarer pour que cela fonctionne?
J'ai explorer deux piste (qui fonctionne) :
- Ajouter le validateur dans le cas d'un insert
- Ajouter un teste sur la présence de l'id dans le validateur ?
Mais je souhaiterais savoir si ma première démarche est possible/bonne ?
Hors ligne
J'avais même pas fait attention ! Du coup je fais des modifications aussi..
La 1ère solution est à éviter, le validateur va être totalement inactif si tu fais un update, du coup tu pourras mettre un "couple champ1/champ2" qui pourrait déjà être enregistré dans la base. Je pense plutôt sur la solution 2 (j'y travaille)
Hors ligne
OK, c'est bon. Il faut rajouter un attribut dans la classe (l'id de la ligne à modifier). Si elle est remplie, il faut rajouter une condition "clé primaire<>id" dans la méthode _query, et le tour est joué !
Hors ligne