Редактирование формы Zend и проверка базы данных Zend Не существует записей
Я постепенно развиваю свои навыки Zend, создавая несколько полезных веб-сайтов для собственного использования. Я использую формы Zend и проверку формы и до сих пор был счастлив, что понимаю, как работает Zend. Однако я немного смущен тем, как использовать Zend_Validate_Db_NoRecordExists() в контексте формы редактирования и поля, которое сопоставляется со столбцом базы данных, который должен быть уникальным.
Например, используя эту простую таблицу
TABLE Test
(
ID INT AUTO_INCREMENT,
Data INT UNIQUE
);
Если бы я был просто добавив новую строку в тест таблицы, я мог бы добавить валидатор в элемент формы Zend для поля данных как такового:
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data') )
При проверке формы этот валидатор проверит, что содержимое элемента данных еще не существует в таблице. Таким образом, вставка в тест может продолжаться без нарушения УНИКАЛЬНОГО квалификатора полей данных.
Однако при редактировании существующей строки тестовой таблицы ситуация иная. В этом случае валидатору необходимо проверить, что элемент значение соответствует одному из двух взаимоисключающих условий:
Пользователь изменил значение элемента, и новое значение в настоящее время не существует в таблице.
Пользователь Не изменил значение элемента. Таким образом, значение действительно в настоящее время существует в таблице (и это нормально).
В Документах по проверке Zend говорится о добавлении параметра в средство проверки NoRecordExists() с целью исключения записи из процесса проверки. Идея состоит в том, чтобы "проверить таблицу на наличие любых совпадающих строк, но игнорировать любые совпадения, в которых поле a имеет это конкретное значение". Такой вариант использования необходим для проверки элемента при редактировании таблицы. Псевдокод для этого в 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, когда форма была первоначально заполнена данными, то есть значением данных, первоначально считанным из строки тестовой таблицы. Но в типичных шаблонах Zend форма создается и заполняется в два отдельных этапа, что исключает привязку значения исключения к желаемому значению элемента.
Следующий код Zend psuedo указывает, где Я бы хотел, чтобы произошла привязка значения $ к валидатору 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 answers
Вот как это делается:
- В свою ФОРМУ вы добавляете этот валидатор (например, поле электронной почты):
$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()))
{
....
Вот и все!
Это также будет работать:
$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())) {
Надеюсь, это поможет вам, люди!
Спасибо