Zend Form Edit и Zend_Validate_Db_NoRecordExists - PullRequest
10 голосов
/ 02 февраля 2010

Я постепенно наращиваю свои навыки Zend, создавая некоторые служебные веб-сайты для своего собственного использования.Я использовал Zend Forms и валидацию форм и до сих пор был счастлив, что понял, как Zend работает.Однако меня немного смущает то, как использовать Zend_Validate_Db_NoRecordExists () в контексте формы редактирования и поля, которое сопоставляется со столбцом базы данных, который должен быть уникальным.

Например, с использованием этой простой таблицы

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

Если бы я просто добавлял новую строку в тест таблицы, я мог бы добавить валидатор к элементу Zend Form для поля данных следующим образом:

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

При валидации формы этот валидатор будетубедитесь, что содержимое элемента Data еще не существует в таблице.Таким образом, вставка в Test может выполняться без нарушения квалификатора UNIQUE полей данных.

Однако при редактировании существующей строки таблицы Test ситуация иная.В этом случае средство проверки должно проверить, что значение элемента соответствует одному из двух взаимоисключающих условий:

  1. Пользователь изменил значение элемента, и новое значение в настоящее время не существует втаблица.

  2. Пользователь Не изменил значение элемента.Таким образом, значение действительно в настоящее время существует в таблице (и это нормально).

Документы Zend Validation Zend говорят о добавлении параметра ввалидатор NoRecordExists () с целью исключения записей из процесса валидации.Идея заключалась в том, чтобы «проверить таблицу на предмет совпадения строк, но игнорировать любые попадания, где поле имеет это конкретное значение».Такой вариант использования - это то, что нужно для проверки элемента при редактировании таблицы.Псевдокод для этого в 1.9 выглядит примерно так (на самом деле я получил это из исходного кода 1.9 - я думаю, что текущие документы могут быть неправильными):

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

Проблема в том, что значениебыть исключенным ($ Value) привязывается к валидатору в момент его создания (также при создании экземпляра формы).Но когда форма редактирует запись, это значение необходимо привязать к содержимому поля $ data, когда форма изначально была заполнена данными - т.е. значение Data, первоначально считанное из строки таблицы Test.Но в типичных шаблонах Zend создается и заполняется форма в два отдельных этапа, что исключает привязку значения исключения к требуемому значению элемента.

Следующий код Zend psuedo отмечает, где я хотел бы, чтобы произошла привязка $ Value к валидатору NoRecordExists () (и обратите внимание, что это обычный шаблон контроллера Zend):

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

Я мог бы создать подкласс Zend_Form и переопределить метод populate (), чтобы выполнить однократную вставку валидатора NoRecordExists () в начальное заполнение формы, но мне это кажется большим взломом.Итак, я хотел знать, что думают другие люди, и уже есть какой-то шаблон, который решает эту проблему?

Редактировать 2009-02-04

Я былдумая, что единственное достойное решение этой проблемы - написать собственный валидатор и забыть о версии Zend.Моя форма имеет идентификатор записи как скрытое поле, поэтому, учитывая имена таблиц и столбцов, я мог бы создать некоторый SQL для проверки на уникальность и исключить строку с идентификатором такого рода.Конечно, это заставило меня задуматься о том, как связать форму со слоем дБ, который должна скрывать Модель!

Ответы [ 7 ]

6 голосов
/ 03 марта 2011

Вот как это делается:

  1. В вашей ФОРМЕ вы добавите этот валидатор (например, поле электронной почты):

$email->addValidator('Db_NoRecordExists', true, array('table' => 'user', 'field' => 'email'));
  1. Не добавляйте пользовательское сообщение об ошибке для этого, так как после этого оно не работает для меня, например:

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

  1. В вашем контроллере добавьте это:

/* 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()))
                {

    ....

Вот и все!

4 голосов
/ 20 августа 2012

Это также будет работать:

$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'
                    )
                )
            )
        )
    ));
1 голос
/ 07 мая 2011
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.');      
    }

Теперь вы можете использовать:

$form = new Form_Test(array('id'=>$id));
1 голос
/ 21 марта 2011
1 голос
/ 09 февраля 2010

Изучив исчерпывающий ответ, я решил, что у меня будет собственный валидатор

0 голосов
/ 16 августа 2012

Я только что попробовал этот пример для email address уникальности, и он отлично работает с нижеприведенными материалами:

1] В моей форме:

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

Вот что-то особенное, что мне нужно было добавить для unique email address для работы:

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

2] В моем контроллере:

$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())) {

Надеюсь, это поможет вам, люди!

Спасибо

0 голосов
/ 02 февраля 2010

Вы можете просто позвонить $form->getElement('input')->removeValidator('Zend_Validator_Db_NoRecordExists'); вместо предоставления исключения.

...