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