1

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

我已经检查过 ZF2 解决方案。http://framework.zend.com/manual/2.2/en/modules/zend.validator.db.html# exclude-records。虽然这种处理复合键的方法看起来不是理想的方法,但我仍然在尝试它,因为它看起来只是内置的方式。现在它要求我提供第二个字段的值(排除中的值选项),这又是一个问题。正如我正在尝试的那样

$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' => [?],
                ),
            )
        ),
     )
 ));

我如何获得这个值,因为表单是绝对独立的类/文件,而不是我提交表单值的控制器。这个问题是否存在一些更好的架构解决方案或者一些将提交的字段值传递给表单类的黑客只是解决方案?

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

4

3 回答 3

1

您可以完成表格中的所有工作。为此,您可以将表单定义为模块Module.php中的工厂

模块.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;
            },
        ),
    );
}

当您想使用表单时,就像在控制器中使用此代码一样简单:

class MyController extends AbstractActionController
{
    public function createAction() {
        $form = $this->getServiceLocator()->get( 'my_form' ) );
        (...)
    }
}

还有你的MyForm.php

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,您可以在其中找到bid构建NoRecordExists过滤器所需的价值。

于 2014-07-22T15:13:12.270 回答
0

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

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

验证器也并非旨在验证多个字段,因为它们以 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' 
        ),
    )
),
于 2014-07-23T12:28:33.390 回答
0

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

getInputFilter($gid, $bid)

然后在控制器上,当您设置过滤器时,您传递 2 个参数,然后检查为 $form->isValid(); ...

替代试试这个:

                array(
                    'name' => 'Db\NoRecordExists',
                    'options' => array(
                        'table' => 'gtable',
                        'field' => 'gid',
                        'adapter' => $this->dbAdapter,
                    ),
                ),
于 2014-07-21T14:04:31.543 回答