如何在编辑表单中使用DoctrineModule\Validator\NoObjectExists - Zend Framework 2和Doctrine 2

4

在同时用于编辑和保存的 Zend 表单中,如何最有效地使用 DoctrineModule\Validator\NoObjectExists 验证器?因为当我使用相同的表单来保存已编辑的值时,它会验证对象是否存在并标记表单无效。


请查看我在此处的答案:http://stackoverflow.com/questions/20680700/zf2-inputfilter-doctrine-noobjectexists-editing-object-does-not-validate#answer-29318872 - blackbishop
3个回答

6

几周前,我使用自定义筛选器中的辅助方法解决了相同的问题。我不确定这是否是正确的方法,但它有效。

  1. 编写一个扩展Zend\InputFilter\InputFilter的自定义输入过滤器。
  2. 在筛选器的init()方法中添加通用筛选器和验证器。
  3. 在输入过滤器中编写一个辅助方法,将Doctrine的existence验证器附加到当前验证器链中,例如下面的示例。
  4. 在创建新对象时,向您的过滤器实例添加存在验证器,而在编辑时使用通用过滤器实例。

所以,

<?php
/**
 * Baz filter
 */
class BazFilter extends Zend\InputFilter\InputFilter
{

/**
 * This method will be triggered automatically when you retrive baz filter via inputfiltermanager.
 */
public function init() 
{
    // Define your input names, types, validators and filters as arrays
    $this->add(array(
        'name' => 'code',
        'required' => true,
        'validators' => array(),
        'filters' => array()
    ));

    $this->add( array(...) );
    $this->add( array(...) );
    // ...
}

/**
 * Appends doctrine's noobjectexists validator to validator chain only when required.
 * 
 * @access public
 * @param \Doctrine\ORM\EntityRepository $repository
 * @return \Zend\InputFilter\InputFilter
 */
public function appendExistenceValidator(\Doctrine\ORM\EntityRepository $repository)
{
     $validatorSignature = array(
        'name' => 'code',
        'validators' => array(
            array(
                'name' => 'DoctrineModule\Validator\NoObjectExists',
                'options' => array(
                    'object_repository' => $repository,
                    'fields' => 'code',
                    'messages' => array( NoObjectExists::ERROR_OBJECT_FOUND => "This object with code already exists in database." )
                )
            )
        )
    );
    $validator = $this->getFactory()->createInput( $validatorSignature );
    $this->add($validator);
    return $this;
    }
}

最后,编辑表单时,请将此输入过滤器附加到您的表单中:
// $form = your form instance
// $filter = Bazfilter instance
$form->setData($postData)->setInputFilter( $filter );
if( $form->isValid() === false ) {
    // ...
}

创建时:

// $filter = bazfilter instance
$repository = $entityManager->getRepository('Your\Entity\Name');
$filter->appendExistenceValidator( $repository ); // <-- Notice this line

$form->setData($postData)->setInputFilter( $filter );
if( $form->isValid() === false ) {
    // ...
}

2
所以,既然你正在编辑一个用户,你可以给他一个已经存在的电子邮件地址... - Dennis D.

1

看起来很不错,但 isValid 会清空绑定到表单的实体。 - shukshin.ivan
这不会使新表单无效吗?因为数据库中该字段没有唯一记录。 - CoCoMo

0

我尝试在表单中使用DoctrineModule\Validator\NoObjectExists,它可以防止更新保持唯一字段不变。正如@Tadej所提到的 - 使用UniqueObject。这是一个示例表单:

class ExampleForm extends Form implements InputFilterProviderInterface
{
    /**
    * @var EntityManager
    */
    private $entityManager;

    /**
    * @var Repository
    */
    private $repository;

    /**
    * ExampleForm constructor.
    *
    * @param EntityManager $entityManager
    * @param Repository $repository
    */
    public function __construct(EntityManager $entityManager, Repository $repository)
    {
        $this->entityManager = $entityManager;
        $this->repository    = $repository;
        $this->add(
            [
                'type'       => Text::class,
                'name'       => 'name',
                'options'    => [
                    'label' => _('Name *')
                ],
                'attributes' => [
                    'class' => 'form-control',
                ],
            ]
        );
    }

    /**
    * @return array
    */
    public function getInputFilterSpecification()
    {
        return [
            'name'     => [
                'required'   => true,
                'filters'    => [
                ],
                'validators' => [
                    [
                        'name'    => UniqueObject::class,
                        'options' => [
                            'object_manager'    => $this->entityManager,
                            'object_repository' => $this->repository,
                            'fields'            => ['name'],
                            'use_context'       => true,
                            'messages'          => [
                                UniqueObject::ERROR_OBJECT_NOT_UNIQUE => "Name '%value%' is already in use",
                            ]
                        ]
                    ]
                ]
            ],
        ];
    }
}

请注意'use_context'选项的使用 - 如果字段不是主键,则必须使用它。'messages'是可选的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接