Validation ZF2和x2B;复合密钥上的重复表单验证

Validation ZF2和x2B;复合密钥上的重复表单验证,validation,zend-framework2,db2,duplicates,zend-form2,Validation,Zend Framework2,Db2,Duplicates,Zend Form2,我有一个在两个字段(gid,bid)上有主键的表单。我需要添加验证来阻止数据库中的重复条目 我已就此与ZF2解决方案进行了核对。虽然这种处理复合键的方法看起来不是理想的方法,但我仍然在尝试,因为它看起来只是一种内置方式。现在需要我提供第二个字段的值(排除中的值选项),这也是一个问题。因为我正在尝试 $inputFilter->add(array( 'name' => 'gid', 'required' => true, 'validator

我有一个在两个字段(gid,bid)上有主键的表单。我需要添加验证来阻止数据库中的重复条目

我已就此与ZF2解决方案进行了核对。虽然这种处理复合键的方法看起来不是理想的方法,但我仍然在尝试,因为它看起来只是一种内置方式。现在需要我提供第二个字段的值(排除中的值选项),这也是一个问题。因为我正在尝试

$inputFilter->add(array(
     'name'     => 'gid',
     'required' => true,
     'validators' => array(
         array(
                'name' => 'NotEmpty',
                'options' => array(
                    'messages' => array(
                        'isEmpty' => 'required'
                    ),
                 ),
         ),
         array (
            'name' => 'Zend\Validator\Db\NoRecordExists',
            'options' => array (
                'table' => 'gtable',
                'field' => 'gid',
                'adapter' => $this->dbAdapter,
                'messages' => array(
                    \Zend\Validator\Db\NoRecordExists::ERROR_RECORD_FOUND => 'The specified key already exists in database' 
                ),
                'exclude' => array(
                    'field' => 'bid',
                    'value' => [?],
                ),
            )
        ),
     )
 ));
我如何得到这个值,因为表单是绝对独立的类/文件,而不是控制器,在控制器中我有提交的表单值。这个问题是否存在更好的体系结构解决方案,或者将提交的字段值传递给表单类是唯一的解决方案


注意:我不赞成为此任务构建验证插件,因为短时间是功能的限制。

您可以向getInputFilter添加参数,如下所示:

getInputFilter($gid, $bid)
然后在控制器上,当设置过滤器时,传递2个参数,然后只需检查$form->isValid()

另一种选择:试试这个:

                array(
                    'name' => 'Db\NoRecordExists',
                    'options' => array(
                        'table' => 'gtable',
                        'field' => 'gid',
                        'adapter' => $this->dbAdapter,
                    ),
                ),

你可以用你的方式做所有的工作。为了实现这一点,您可以在模块module.php中将表单定义为工厂

Module.php

use MyNamespace\MyForm;

//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;
            },
        ),
    );
}
use Zend\Form\Form;

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() );
    }
}
当您想要使用表单时,只需在控制器中使用以下代码即可:

class MyController extends AbstractActionController
{
    public function createAction() {
        $form = $this->getServiceLocator()->get( 'my_form' ) );
        (...)
    }
}
以及您的MyForm.php

use MyNamespace\MyForm;

//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;
            },
        ),
    );
}
use Zend\Form\Form;

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

通过这种方式,您可以在表单中使用服务管理器。还有公共的
postData
,您可以在这里找到构建
NoRecordExists
过滤器所需的
bid
值。

我不确定您的用例。如果要添加数据库条目,则该表的主键在插入之前是未知的-如果有外键约束,则可以处理数据库中的异常

我不赞成为此任务构建验证插件

验证器也不是为了验证多个字段而设计的,因为它们以1-1的方式附加到表单元素。因此,您需要创建自己的

下面的示例未经测试,因此将其作为该方法的示例,而不是工作代码

关键位是
isValid
方法

namespace MyModule\Validator\Db;

use Zend\Validator\Db\NoRecordExists;

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]) && 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' => 'MyModule\Validator\Db\CompositeNoRecordExists',
    'options' => array (
        'table'    => 'gtable',
        'field'    => 'gid',
        'field2'   => 'bid',
        'adapter'  => $this->dbAdapter,
        'messages' => array(
            \Zend\Validator\Db\NoRecordExists::ERROR_RECORD_FOUND => 'The specified key already exists in database' 
        ),
    )
),

我不知道是什么问题,但没有执行任何验证,数据库每次都会抛出重复错误。我检查了bjyprofile,发现执行了正确的查询,但没有出现验证错误。能否在控制器上发布设置过滤器的代码?
$postData=$request->getPost()$表单->设置输入过滤器($表单->获取输入过滤器($postData['bid'])确定,因此尝试在方法上使用不同的名称,称之为getInputFilterCustom($bid,…);因为现在您正在覆盖表单上当前的getInputFilter,这总是会带来不需要的行为。但是所有其他验证都可以正常工作。我只是在教程中做了一个改动,我将inputfilter放在表单本身而不是模型中。实际上,@ins0的
bid
值来自哪里?@ins0,这是我的问题。解决方案工作正常,验证工作正常。只有一个问题只有一个字段显示错误,但我认为这不容易修复。
exclude
选项是一个混合变量。这意味着它可以是一个包含
字段
键的数组,也可以是一个类似
gid=[?]和bid=[?]的字符串。
。您可以这样尝试,并将此
exclude
设置添加到两个输入的验证器中。