php zend-framework zend-db zend-validate

php - Zend Form Edit y Zend_Validate_Db_NoRecordExists



zend-framework zend-db (7)

Poco a poco voy mejorando mis habilidades con Zend construyendo algunos sitios web de utilidad para mi propio uso. He estado usando Formularios Zend y validación de formularios y hasta ahora he estado feliz de haber comprendido la forma de hacer las cosas de Zend. Sin embargo, estoy un poco confundido con el uso de Zend_Validate_Db_NoRecordExists () en el contexto de un formulario de edición y un campo que se asigna a la columna de la base de datos que tiene que ser único.

Por ejemplo, usando esta tabla simple

TABLE Test ( ID INT AUTO_INCREMENT, Data INT UNIQUE );

Si simplemente agregara una nueva fila a Table Test, podría agregar un validador al elemento Zend Form para el campo de datos como tal:

$data = new Zend_Form_Element_Text(''Data''); $data->addValidator( new Zend_Validate_Db_NoRecordExists(''Test'', ''Data'') )

En la validación del formulario, este validador verificará que el contenido del elemento Datos aún no exista en la tabla. Por lo tanto, la inserción en Prueba puede continuar sin violar el calificador UNIQUE de los campos de Datos.

Sin embargo, la situación es diferente cuando se edita una fila existente de la tabla de prueba. En ese caso, el validador debe verificar que el valor del elemento cumple con una de las dos condiciones de condiciones mutuamente excluyentes:

  1. El usuario ha cambiado el valor del elemento, y el nuevo valor no existe actualmente en la tabla.

  2. El usuario no ha cambiado el valor del elemento. Por lo tanto, el valor existe actualmente en la tabla (y esto está bien).

Los Zend Validation Docs hablan de agregar un parámetro al validador NoRecordExists () con el propósito de excluir registros del proceso de validación. La idea es "validar la tabla buscando las filas que coincidan, pero ignorar las visitas donde el campo a tenga este valor específico". Tal caso de uso es lo que se necesita para validar el elemento al editar una tabla. El pseudo código para hacer esto en 1.9 es así (en realidad lo obtuve del código fuente 1.9, creo que los documentos actuales pueden estar equivocados):

$data = new Zend_Form_Element_Text(''Data''); $data->addValidator( new Zend_Validate_Db_NoRecordExists(''Test'', ''Data'', array (''field''=>''Data'', ''Value''=> $Value) );

El problema es que el valor que se va a excluir ($ Value) está vinculado al validador en el momento en que se crea una instancia (también cuando se crea una instancia del formulario). Pero cuando el formulario está editando un registro, ese valor debe vincularse al contenido del campo $ data cuando el formulario se rellenó inicialmente con datos, es decir, el valor de Datos inicialmente leído de la fila de la tabla de Prueba. Pero en los patrones Zend típicos, un formulario se crea una instancia y se rellena en dos pasos separados que excluyen el enlace del valor de exclusión con el valor del elemento deseado.

El siguiente código Zend psuedo marca donde me gustaría que se produzca el enlace de $ Value al validador NoRecordExists () (y tenga en cuenta que este es un patrón de controlador Zend común):

$form = new Form() if (is Post) { $formData = GetPostData() if ($form->isValid($formData)) { Update Table with $formData Redirect out of here } else { $form->populate($formData) } } else { $RowData = Get Data from Table $form->populate($RowData) <=== This is where I want (''value'' => $Value) bound }

Podría subclasificar Zend_Form y anular el método populate () para hacer una inserción de una sola vez del validador NoRecordExists () en la población de formularios inicial, pero eso me parece un gran truco. Entonces, quería saber qué piensan los demás y ¿hay algún patrón ya escrito que resuelva este problema?

Editar 2009-02-04

He estado pensando que la única solución decente para este problema es escribir un validador personalizado y olvidarme de la versión de Zend. Mi formulario tiene el ID de registro como campo oculto, por lo que, dados los nombres de tabla y columna, podría crear algunos SQL para probar la exclusividad y excluir la fila con una ID de tal. Por supuesto, esto me hizo pensar en cómo estaría atando el formulario a la capa de dB que se supone que oculta el Modelo.


Simplemente puede llamar a $form->getElement(''input'')->removeValidator(''Zend_Validator_Db_NoRecordExists''); en lugar de suministrar la exclusión.


Después de revisar la abrumadora respuesta, he decidido que voy con un validador personalizado


Acabo de probar este ejemplo para la singularidad de la email address y funciona perfectamente con productos siguientes:

1] En mi forma:

// Add an email element $this->addElement(''text'', ''email'', array( ''label'' => ''Email :'', ''required'' => true, ''filters'' => array(''StringTrim''), ''validators'' => array( ''EmailAddress'', ) ));

Aquí hay algo especial que necesitaba agregar para que funcione una unique email address :

$email = new Zend_Form_Element_Text(''email''); $email->addValidator(''Db_NoRecordExists'', true, array(''table'' => ''guestbook'', ''field'' => ''email''));

2] En mi controlador:

$form->getElement(''email'') ->addValidator(''Db_NoRecordExists'', false, array(''table'' => ''guestbook'', ''field'' => ''email'', ''exclude'' => array (''field'' => ''id'', ''value'' => $request->get(''id'')))); if ($this->getRequest()->isPost()) { if ($form->isValid($request->getPost())) {

Espero que te ayude a la gente!

Gracias


Así es como se hace:

  1. En tu FORMA, agregas este validador (por ejemplo, campo de correo electrónico):

$email->addValidator(''Db_NoRecordExists'', true, array(''table'' => ''user'', ''field'' => ''email''));

  1. No agregue un mensaje de error personalizado para esto, ya que después de eso no funcionó, por ejemplo:

$email->getValidator(''Db_NoRecordExists'')->setMessage(''This email is already registered.'');

  1. En tu Controlador agrega esto:

/* Don''t check for Db_NoRecordExists if editing the same field */ $form->getElement(''email'') ->addValidator(''Db_NoRecordExists'', false, array(''table'' => ''user'', ''field'' => ''email'', ''exclude'' => array (''field'' => ''id'', ''value'' => $this->request->get(''id'')))); And after this you do verifications, e.g.: if ($this->getRequest()->isPost()) { if($form->isValid($this->getRequest()->getPost())) { ....

¡Eso es!


Esto también funcionará:

$this->addElement(''text'', ''email'', array( ''label'' => ''Your email address:'', ''required'' => true, ''filters'' => array(''StringTrim''), ''validators'' => array( ''EmailAddress'', array(''Db_NoRecordExists'', true, array( ''table'' => ''guestbook'', ''field'' => ''email'', ''messages'' => array( ''recordFound'' => ''Email already taken'' ) ) ) ) ));


private $_id; public function setId($id=null) { $this->_id=$id; } public function init() { ..... if(isset($this->_id)){ $email->addValidator(''Db_NoRecordExists'', false, array(''table'' => ''user'', ''field'' => ''email'',''exclude'' => array (''field'' => ''id'', ''value'' => $this->_id) )); $email->getValidator(''Db_NoRecordExists'')->setMessage(''This email is already registered.''); }

Ahora puedes usar:

$form = new Form_Test(array(''id''=>$id));