Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/248.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php ZF2和条令输入过滤器(唯一,ObjectExists),用于具有字段集的新实体和现有实体_Php_Doctrine Orm_Zend Framework2 - Fatal编程技术网

Php ZF2和条令输入过滤器(唯一,ObjectExists),用于具有字段集的新实体和现有实体

Php ZF2和条令输入过滤器(唯一,ObjectExists),用于具有字段集的新实体和现有实体,php,doctrine-orm,zend-framework2,Php,Doctrine Orm,Zend Framework2,我在学习教义,我有一个表格。ZF2和带“电子邮件”字段的条令。 这个字段必须是唯一的,所以我需要它的验证器。我也在使用字段集(这里很重要)。问题是,当我使用: DoctrineModule\Validator\UniqueObject 创建新实体是不可能的。此验证器需要主键进行比较。 验证程序转储错误,消息为: 预期上下文包含itemId itemId是我的主键 很明显,我需要使用UniqueObject进行更新,并且: DoctrineModule\Validator\NoObjectExi

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

DoctrineModule\Validator\UniqueObject
创建新实体是不可能的。此验证器需要主键进行比较。 验证程序转储错误,消息为:

预期上下文包含itemId

itemId是我的主键

很明显,我需要使用UniqueObject进行更新,并且:

DoctrineModule\Validator\NoObjectExists
对于新实体。问题是:

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

或者,如果可能更好:如何将唯一验证器与zend form字段集的新记录和现有记录一起使用

若我把它放在表单中,若实体是新的或不是,我需要在控制器中修改它。这不是个好主意

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

----编辑

我看过文档,知道如何使用unique对象,但我遇到了前面说过的错误:“预期上下文包含itemId”。我认为问题在于字段集(我正在使用它)。我不明白怎么做(文档中的文本):

如果省略了use_context选项或将其设置为false,则必须 将包含字段和标识符值的数组传递到 isValid()。使用Zend\Form时,如果您 使用字段集


好的,我正在使用字段集,那么现在我能做什么呢?当我使用zend forms时,如何将正确的值传递给isValid?

您只需在表单输入筛选器规范中使用UniqueObject validator,如下所示:

    '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!'
                    ),
                ),
            )
        ),
    ),
您可以通过此链接找到更多详细信息:

使用
UniqueObject
验证器,您需要在上下文中具有标识符字段。因此,只有当
电子邮件
列是您的
电子邮件
实体的标识符列时,它才会起作用?您还有一个
id
列。最好在您的用户案例中使用
NoObjectExists
验证器:

'email' => array(
    'validators' => array(
        array(
            'name' => 'DoctrineModule\Validator\NoObjectExists',
            'options' => array(
                'object_repository' => $entityManager->getRepository(
                    'Application\Entity\Email'
                ),
                'fields' => 'email'
            )
        )
    )
)
你也可以找到这个例子

编辑 关于分离更新和新输入过滤器的逻辑,我建议创建两个文件夹。最好这样严格分开,否则很可能会出错。例如,你可以这样做(但这完全取决于你个人的喜好,这是如何组织的)

一个用于更新资源:

Application/InputFilter/Update
    UserInputFilter
然后在控制器中,您可以执行以下操作:

<?php

namespace Application\Controller;

use Application\InputFilter\Create;
use Application\InputFilter\Update;

class UserController{

    public function updateAction()
    {
        $inputFilter = new Update\UserInputFilter();
        //... etc
    }

    public function createAction()
    {
        $inputFilter = new Create\UserInputFilter();
        //... etc
    }
}

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

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

}

我将展示我的解决方案,我认为如果有人想将验证器保存在表单中,这是非常好的。在我的字段集中,我有一个方法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和字段集。

新记录上的UniqueObject存在错误。需要主id密钥才能工作错误到底是什么?我正在使用上述代码,它对新记录和现有记录都有效!我编辑了我的问题,错误是:预期上下文包含itemId。我试着使用上下文false/True我认为问题在于字段集(我在使用它)。但我在主字段集中创建了id字段,主表单,和我使用验证器的字段集相同,仍然是相同的错误。从手册中我看到,如果我使用fieldset,我需要传递两个值,但我不知道如何传递,因为我使用fieldset时存在上下文问题。我看不到别的路。但问题是“为现有实体和新实体存储不同输入过滤器规范的最佳方式是什么?”@Daimos这在很大程度上取决于您的个人偏好。有很多方法可以做到这一点,但我在我的答案中添加了一个示例…谢谢,您如何看待将输入过滤器存储在条令存储库中?我看到了很多这样的例子,但如果它的新回购协议或no@Daimos,我认为你不应该用这样的逻辑把你的存储库弄得乱七八糟。如果你问我,与InputFilter相关的代码不属于那里。与向实体添加输入过滤器配置的人员相同;我不喜欢它。但同样,对于如何做到这一点,没有严格的指导方针。这是个人喜好。很好的解决方案,谢谢。Im将实体对象绑定到表单,这样我就可以将它传递给验证器,检查它是否是新的,并且我不需要额外的查询。但仍然有自己的验证器是一个很好的方法,我现在的方法是切换ObjectExist和Unique,以适应新的和现有的objectsCould+10;)正是我想要的,看看我关于这个问题的答案。
                    '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)
                        )
                    )
                ),
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',
                    )
                )
            )
        )
    );
}