#validation #zend-framework2 #db2 #duplicates #zend-form2
#проверка #zend-framework2 #db2 #дубликаты #zend-form2
Вопрос:
У меня есть форма, имеющая первичный ключ для двух полей (gid, bid). Мне нужно добавить проверку, чтобы блокировать повторяющиеся записи в базе данных.
Для этого я проверил решение ZF2 . http://framework.zend.com/manual/2.2/en/modules/zend.validator.db.html#excluding-records . Хотя такой подход к обработке составных ключей выглядит не идеально, но все же я пробую его, потому что он выглядит как единственный встроенный способ. Теперь мне требуется указать значение второго поля (параметр value в exclude), что снова является проблемой. Поскольку я пытаюсь это
$inputFilter->add(array(
'name' => 'gid',
'required' => true,
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'messages' => array(
'isEmpty' => 'required'
),
),
),
array (
'name' => 'ZendValidatorDbNoRecordExists',
'options' => array (
'table' => 'gtable',
'field' => 'gid',
'adapter' => $this->dbAdapter,
'messages' => array(
ZendValidatorDbNoRecordExists::ERROR_RECORD_FOUND => 'The specified key already exists in database'
),
'exclude' => array(
'field' => 'bid',
'value' => [?],
),
)
),
)
));
Как мне получить это значение, поскольку форма является абсолютно отдельным классом / файлом, чем контроллер, где у меня есть отправленные значения формы. Существует ли какое-то лучшее архитектурное решение этой проблемы или единственным решением является какой-то взлом для передачи отправленного значения поля в класс Form?
Примечание: я не сторонник создания моего плагина проверки для этой задачи, поскольку короткое время ограничивает функциональность.
Комментарии:
1. откуда берется
bid
значение?2. @ins0, на самом деле это мой вопрос.
Ответ №1:
Вы можете выполнить всю работу в своей форме. Для достижения этого вы могли бы определить свои формы как фабрики в вашем модуле Module.php.
Module.php
use MyNamespaceMyForm;
//NOTE THAT THE SERVICE MANAGER IS INJECTED. YOUR FORM COULD RECEIVE IT THROUGH THE CONSTRUCTOR
public function getServiceConfig()
{
return array(
'factories' => array(
'my_form' => function( $sm ) {
$form = new MyForm( $sm );
return $form;
},
),
);
}
Если вы хотите использовать форму, это так же просто, как использовать этот код в вашем контроллере:
class MyController extends AbstractActionController
{
public function createAction() {
$form = $this->getServiceLocator()->get( 'my_form' ) );
(...)
}
}
И ваш MyForm.php
use ZendFormForm;
class MyForm extends Form
{
public $serviceManager, $request, $postData;
public function __construct( $serviceManager ) {
parent::__construct( null );
$this->serviceManager = $serviceManager;
$this->request = $serviceManager->get( 'Application')->getMvcEvent()->getRequest();
$this->postData = get_object_vars( $this->request->getPost() );
}
}
Таким образом, вы можете воспользоваться Service Manager в своей форме. И общедоступный, postData
где вы найдете bid
значение, которое ищете для построения своего NoRecordExists
фильтра.
Комментарии:
1. Решение работает, и проверка выполняется нормально. Только одна проблема, только в одном поле отображаются ошибки, но, как я полагаю, это нелегко исправить.
2.
exclude
Вариантом является смешанный параметр. Это означает, что это может быть массив с ключамиfield
иvalue
или строка типаgid = [?] AND bid = [?]
. Вы могли бы попробовать это таким образом и добавить этотexclude
параметр к средствам проверки обоих входных данных.
Ответ №2:
Вы могли бы добавить параметры в getInputFilter, например, так :
getInputFilter($gid, $bid)
И затем на контроллере, когда вы устанавливаете фильтр, вы передаете 2 параметра, а затем просто проверяете как $form->isValid(); …
Альтернативный вариант попробуйте это:
array(
'name' => 'DbNoRecordExists',
'options' => array(
'table' => 'gtable',
'field' => 'gid',
'adapter' => $this->dbAdapter,
),
),
Комментарии:
1. Я не знаю, в чем проблема, но проверка не выполняется, И база данных каждый раз выдает повторяющуюся ошибку. Я проверил через bjyprofile и обнаружил, что запрос выполнен правильно, но ошибка проверки не выдается.
2. можете ли вы опубликовать код настройки фильтра на контроллере?
3.
$postData = $request->getPost();$form->setInputFilter($form->getInputFilter($postData['bid']));
4. Хорошо, поэтому попробуйте использовать другое имя для вашего метода, назовите его getInputFilterCustom($bid, …); потому что теперь вы переопределяете текущий getInputFilter в форме, а это всегда приводит к нежелательному поведению.
5. Но все остальные проверки просто отлично работают. У меня есть только одно изменение из руководства, в котором я помещаю inputfilter в саму форму вместо Model.
Ответ №3:
Я не уверен в вашем варианте использования. Если бы вы добавили запись в базе данных, первичные ключи для этой таблицы не были бы известны до тех пор, пока вы все равно не вставите — если у вас есть ограничения на внешний ключ, вы могли бы обработать исключение из базы данных.
Я не сторонник создания моего плагина проверки для этой задачи
Средство проверки также не предназначено для проверки нескольких полей, поскольку они прикреплены к элементу формы по принципу 1-1. Поэтому вам нужно будет создать свою собственную.
Приведенный ниже пример НЕ тестировался, поэтому воспринимайте его скорее как пример подхода, чем как рабочий код.
Бит ключа — это isValid
метод.
namespace MyModuleValidatorDb;
use ZendValidatorDbNoRecordExists;
class CompositeNoRecordExists extends NoRecordExists
{
protected $field2;
protected $field2Value;
public function __construct($options = null)
{
parent::__construct($options);
if (array_key_exists('field2', $options)) {
$this->setField2($options['field2']);
} else {
throw new BadMethodCallException('Missing field2 option!');
}
}
protected function setField2Value(array $context)
{
if (! isset($context[$this->field2])) {
throw new BadMethodCallException('Unable to find value for field 2');
}
$this->field2Value = $context[$this->field2];
}
public function isValid($value)
{
// The isValid() method is actually given a 2nd argument called $context
// Which is injected by the inputFilter, via the input and into the validator chain
// $context contains all of RAW form element values, keyed by thier element name.
// Unfortunately due to the ValidatorInterface you are unable to add this to the method
// signature. So you will need to be 'creative':
$args = func_get_args();
if (isset($args[1]) amp;amp; is_array($args[1])) {
$this->setField2Value($args[1]);
} else {
throw new BadMethodCallException('Missing validator context');
}
return parent::isValid($value);
}
public function getSelect()
{
$select = parent::getSelect();
$select->where->equalTo($this->field2, $this->field2Value);
return $select;
}
}
Затем все, что вам нужно будет сделать, это обновить конфигурацию средства проверки, добавив field2
имя поля.
array (
'name' => 'MyModuleValidatorDbCompositeNoRecordExists',
'options' => array (
'table' => 'gtable',
'field' => 'gid',
'field2' => 'bid',
'adapter' => $this->dbAdapter,
'messages' => array(
ZendValidatorDbNoRecordExists::ERROR_RECORD_FOUND => 'The specified key already exists in database'
),
)
),