Я медленно наращиваю свои навыки Zend, создавая некоторые полезные сайты для собственного использования. Я использую Zend Forms и Form validation, и до сих пор был счастлив, что я понимаю способ Zend делать вещи. Однако я немного смущен тем, как использовать Zend_Validate_Db_NoRecordExists () в контексте формы редактирования и поле, которое сопоставляется столбцу базы данных, которое должно быть уникальным.
Например, используя эту простую таблицу
TABLE Test ( ID INT AUTO_INCREMENT, Data INT UNIQUE );
Если бы я просто добавлял новую строку в Table Test, я мог бы добавить валидатор в элемент формы Zend для поля Data как таковой:
$data = new Zend_Form_Element_Text('Data'); $data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data') )
При проверке формы этот валидатор проверяет, что содержимое элемента данных еще не существует в таблице. Таким образом, вставка в Test может идти вперед, не нарушая поля Data data UNIQUE.
Однако при редактировании существующей строки таблицы Test ситуация меняется. В этом случае валидатору необходимо проверить, что значение элемента соответствует одному из двух условий взаимоисключающих условий:
Пользователь изменил значение элемента, и новое значение в настоящее время не существует в таблице.
Пользователь не изменил значение элемента. Таким образом, значение в настоящее время существует в таблице (и это нормально).
В документах по проверке 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, когда форма была сначала заполнена данными – 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 для проверки на уникальность и исключить строку с идентификатором такого типа. Конечно, это заставило меня задуматься о том, как я привяжу форму к слою дБ, который должна скрывать модель.
Вот как это делается:
$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, eg: if ($this->getRequest()->isPost()) { if($form->isValid($this->getRequest()->getPost())) { ....
Это оно!
Это также будет работать:
$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.'); }
Теперь вы можете использовать:
$form = new Form_Test(array('id'=>$id));
Вы можете просто вызвать $form->getElement('input')->removeValidator('Zend_Validator_Db_NoRecordExists');
вместо предоставления исключения.
Я только что попробовал этот пример для уникальности 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())) {
Надеюсь, это поможет вам!
благодаря