And*_*ndy 16 php validation entity symfony doctrine-orm
我想知道是否有一种方法可以在刷新之前比较实体内的验证器中的旧值和新值.
我有一个Server实体,可以呈现一个形式.该实体具有对关系status(N-> 1),其中,当状态从Unracked到Racked,需要检查SSH和FTP对服务器的访问.如果未实现访问,则验证器应该失败.
我已映射验证程序回调方法isServerValid()的内Server如这里所描述的实体
http://symfony.com/doc/current/reference/constraints/Callback.html.我可以通过显然访问'新'值$this->status,但我怎样才能获得原始值?
在伪代码中,这样的东西:
public function isAuthorValid(ExecutionContextInterface $context)
{
$original = ... ; // get old values
if( $this->status !== $original->status && $this->status === 'Racked' && $original->status === 'Unracked' )
{
// check ftp and ssh connection
// $context->addViolationAt('status', 'Unable to connect etc etc');
}
}
Run Code Online (Sandbox Code Playgroud)
提前致谢!
小智 33
Symfony 2.5的完整示例(http://symfony.com/doc/current/cookbook/validation/custom_constraint.html)
在此示例中,实体"NoDecreasingInteger"的字段"integerField"的新值必须高于存储值.
创建约束:
// src/Acme/AcmeBundle/Validator/Constraints/IncrementOnly.php;
<?php
namespace Acme\AcmeBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class IncrementOnly extends Constraint
{
public $message = 'The new value %new% is least than the old %old%';
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
return 'increment_only';
}
}
Run Code Online (Sandbox Code Playgroud)
创建约束验证器:
// src/Acme/AcmeBundle/Validator/Constraints/IncrementOnlyValidator.php
<?php
namespace Acme\AcmeBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Doctrine\ORM\EntityManager;
class IncrementOnlyValidator extends ConstraintValidator
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function validate($object, Constraint $constraint)
{
$new_value = $object->getIntegerField();
$old_data = $this->em
->getUnitOfWork()
->getOriginalEntityData($object);
// $old_data is empty if we create a new NoDecreasingInteger object.
if (is_array($old_data) and !empty($old_data))
{
$old_value = $old_data['integerField'];
if ($new_value < $old_value)
{
$this->context->buildViolation($constraint->message)
->setParameter("%new%", $new_value)
->setParameter('%old%', $old_value)
->addViolation();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
将验证器绑定到实体:
// src/Acme/AcmeBundle/Resources/config/validator.yml
Acme\AcmeBundle\Entity\NoDecreasingInteger:
constraints:
- Acme\AcmeBundle\Validator\Constraints\IncrementOnly: ~
Run Code Online (Sandbox Code Playgroud)
将EntityManager注入IncrementOnlyValidator:
// src/Acme/AcmeBundle/Resources/config/services.yml
services:
validator.increment_only:
class: Acme\AcmeBundle\Validator\Constraints\IncrementOnlyValidator
arguments: ["@doctrine.orm.entity_manager"]
tags:
- { name: validator.constraint_validator, alias: increment_only }
Run Code Online (Sandbox Code Playgroud)
您可以检查控制器操作中的先前值...但这不是一个干净的解决方案!
normal form-validation只能访问绑定到表单的数据...默认情况下不能访问"previous"数据.
您尝试使用的回调约束无法访问容器或任何其他服务...因此您无法轻松访问实体管理器(或任何以前的数据提供程序)以检查以前的值.
你需要的是一个自定义的验证器上一流水平.需要类级别,因为如果要获取实体,则需要访问整个对象而不仅仅是单个值.
验证器本身可能如下所示:
namespace Vendor\YourBundle\Validation\Constraints;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class StatusValidator extends ConstraintValidator
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function validate($status, Constraint $constraint)
{
$em = $this->container->get('doctrine')->getEntityManager('default');
$previousStatus = $em->getRepository('YourBundle:Status')->findOneBy(array('id' => $status->getId()));
// ... do something with the previous status here
if ( $previousStatus->getValue() != $status->getValue() ) {
$this->context->addViolationAt('whatever', $constraint->message, array(), null);
}
}
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
return 'previous_value';
}
}
Run Code Online (Sandbox Code Playgroud)
...然后将验证器注册为服务并将其标记为验证器
services:
validator.previous_value:
class: Vendor\YourBundle\Validation\Constraints\StatusValidator
# example! better inject only the services you need ...
# i.e. ... @doctrine.orm.entity_manager
arguments: [ @service_container ]
tags:
- { name: validator.constraint_validator, alias: previous_value }
Run Code Online (Sandbox Code Playgroud)
最后使用约束为您的状态实体(即使用注释)
use Vendor\YourBundle\Validation\Constraints as MyValidation;
/**
* @MyValidation\StatusValidator
*/
class Status
{
Run Code Online (Sandbox Code Playgroud)