Zend Form Edit и Zend_Validate_Db_NoRecordExists

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

Например, используя эту простую таблицу

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

Если бы я просто добавлял новую строку в Test Table, я мог бы добавить валидатор в элемент формы Zend для поля Data как такового:

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

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

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

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

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

Dend Validation Docs рассказывают о добавлении параметра в средство проверки 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, когда форма была сначала заполнена данными - IE - значение Data, первоначально прочитанное из строки Test table. Но в типичных шаблонах Zend форма создается и заполняется двумя отдельными шагами, что исключает привязку значения exclude к требуемому значению элемента.

Следующие кодовые обозначения 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 для проверки на уникальность и исключить строку с идентификатором такого типа. Конечно, это заставило меня задуматься о том, как я привяжу форму к слою дБ, который должна скрыть модель.

Ответ 1

После рассмотрения подавляющего ответа я решил, что я собираюсь использовать специальный валидатор

Ответ 2

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

  • Я ваш FORM, вы добавляете этот валидатор (например, поле электронной почты):

 

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

 

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

 

  • В контроллере добавьте следующее:

 

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

    ....

Что это!

Ответ 3

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

$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'
                    )
                )
            )
        )
    ));

Ответ 5

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

Ответ 6

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

Ответ 7

Я только что попробовал этот пример для уникальности 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())) {

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

Спасибо