具有字段集

时间:2015-10-31 13:30:12

标签: php doctrine-orm zend-framework2

我正在学习学说,我有一个表格。 ZF2和学说与字段“电子邮件”。 这个字段必须是唯一的,所以我需要验证器。我也使用了字段集(这里很重要)。问题是,当我使用时:

DoctrineModule\Validator\UniqueObject

创建新实体是不可能的。此验证器需要主键进行比较。 带有消息的验证器转储错误:

  

包含itemId的预期上下文

itemId是我的主键。

显而易见,我需要使用UniqueObject进行更新,并且:

DoctrineModule\Validator\NoObjectExists

表示新实体。问题是:

为现有实体和新实体存储不同的输入过滤规范的最佳方法是什么?

或者,如果可能的话,更好:如何使用带有zend表单字段集的新记录和现有记录的唯一验证器。

如果我把它放在表单中,我需要在控制器内修改它,如果实体是新的或没有。不太好主意。

我认为最好的方法是存储输入过滤规范。在实体存储库内部,但我如何检查实体是否是新的?

----编辑

我看到了文档,我知道如何使用唯一对象,但我有如前所述的错误:“包含itemId的预期上下文”。我认为问题在于字段集(即时使用它)。我不明白该怎么做(文档中的文字):

  

如果省略use_context选项或将其设置为false,则必须这样做   将包含fields-和identifier-values的数组传递给   已验证()。使用Zend \ Form时,如果你需要这种行为   使用字段集

好的我正在使用现场集,所以现在我能做什么?我在使用zend表单时如何将正确的值传递给isValid?

4 个答案:

答案 0 :(得分:2)

使用N验证程序,您需要在上下文中包含标识符字段。因此,仅当UniqueObject列是email实体的标识符列时,它才有效吗?您还有一个Email列。最好在您的用户案例中使用id验证程序:

NoObjectExists

您还可以找到此示例in the documentation

修改

关于分离更新和新输入过滤器的逻辑我建议制作两个文件夹。最好将它们严格分开,否则很可能会发生错误。例如,您可以这样做(但这完全取决于您个人喜好如何组织)。

'email' => array(
    'validators' => array(
        array(
            'name' => 'DoctrineModule\Validator\NoObjectExists',
            'options' => array(
                'object_repository' => $entityManager->getRepository(
                    'Application\Entity\Email'
                ),
                'fields' => 'email'
            )
        )
    )
)

一个用于更新资源:

Application/InputFilter/Create
    UserInputFilter

然后在你的控制器中你可以这样做:

Application/InputFilter/Update
    UserInputFilter

答案 1 :(得分:2)

我为我的应用程序开发了它来处理这个问题。希望它会有所帮助

<?php

namespace Application\Validator;

use Zend\Validator\AbstractValidator;

class DbUniqueObject extends AbstractValidator {

const INVALID = 'objectAlreadyExists';

protected $messageTemplates = array(
    self::INVALID => "Field value must be unique in the database (id=%id%)",
);
protected $messageVariables = array(
    'id' => array('options' => 'id'),
);
protected $options          = array(
    'em',
    'entity',
    'field',
    'exclude_id'
);

public function __construct($options = null) {
    $this->options = $options;
    parent::__construct($options);
}

public function isValid($value) {
    $qb = $this->em->createQueryBuilder();
    $qb->select('t')
            ->from($this->entity, 't')
            ->where('t.' . $this->field . '= :field')
            ->setParameter('field', $value);

    if (boolval($this->exclude_id)) {
        $qb->andWhere('t.id <> :id');
        $qb->setParameter('id', $this->exclude_id);
    }
    $result = $qb->getQuery()->getResult();
    if (boolval($result)) {
        $this->options['id'] = $result[0]->getID();
        $this->error(self::INVALID);
        return false;
    }
    return true;
}

public function __get($property) {
    return array_key_exists($property, $this->options) ? $this->options[$property] : parent::__get($property);
}

}

然后在你的输入过滤器中附加到你的表单,只需添加,在'Validators'数组中:

                    'validators' => array(
                    array(
                        'name'    => '\Application\Validator\DbUniqueObject',
                        'options' => array(
                            'em'         => $em, //Entity manager
                            'entity'     => 'Application\Entity\Customer', // Entity name
                            'field'      => 'label', // column name
                            'exclude_id' => $this->customer->getID() : null, // id to exclude (useful in case of editing)
                        )
                    )
                ),

答案 2 :(得分:1)

我会展示我的解决方案,如果有人想在表单中保留验证器,我认为相当不错。在我的fieldset中,我有方法getInputFilterSpecification(),它会自动处理,并在那里:

public function getInputFilterSpecification()
{
    // im bind object new or exist to the form, 
    // so there is a simple way to get it:
    $entity = $this->getObject(); 
    // method to check if object is new or not:
    // $this->_entityManager i have entitymanager passed in constructor
    switch ($this->_entityManager->getUnitOfWork()->getEntityState($entity)) {
        case \Doctrine\ORM\UnitOfWork::STATE_MANAGED:
            // im switch validator, unique for existing:
            $existValidator = 'DoctrineModule\Validator\UniqueObject';
        case \Doctrine\ORM\UnitOfWork::STATE_NEW:
            $existValidator = 'DoctrineModule\Validator\NoObjectExists';
    }
    // propably we can also check if object primary key is empty or not
    // i will test it later

    return array(
        'elementName' => array(
            'required' => true,
            'validators' => array(
                array(
                    'name' => $existValidator,
                    'options' => array(
                        'object_repository' => $this->_entityManager->getRepository('My\Entity'),
                        'object_manager' => $this->_entityManager,
                        'fields' => 'fieldName',
                    )
                )
            )
        )
    );
}

它仍未使用唯一验证器进行测试。也许主键也会有问题,我会在几天内检查一下。但它仍然是基于新节点或现有节点分配正确验证器的简单方法。

我的结论: 唯一验证器不适用于ZF2和字段集。

答案 3 :(得分:0)

您只需要在输入过滤器规范:

中使用UniqueObject验证器,如下所示
    'email' => array(
        'validators' => array(
            array(
                'name' => 'DoctrineModule\Validator\UniqueObject',
                'options' => array(
                    'use_context'       => true,
                    'object_repository' => $this->objectManager->getRepository('Namespace\EntityName'),
                    'object_manager' => $this->objectManager,
                    'fields' => 'email',
                    'messages' => array(
                        'objectNotUnique' => 'Email already exists!'
                    ),
                ),
            )
        ),
    ),

您可以从此链接中找到更多详细信息: https://github.com/doctrine/DoctrineModule/blob/master/docs/validator.md