【问题标题】:Symfony - get an entity object in a field constraint classSymfony - 在字段约束类中获取实体对象
【发布时间】:2017-10-25 22:34:52
【问题描述】:

我创建了我的自定义约束验证器:

class CustomConstraint extends Constraint
{
    public $message = '';
}

class CustomConstraintValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint)
    {
         exit($this->context->getObject()); // returns null
    }
}

docs 中声明:

返回当前验证的对象。

,但对我来说它返回 NULL

附:我不想将此约束分配给实体,只分配给某些表单或字段。

经过验证的我的表单属性:

->add('rejectReasons', null, array(
        'property' => 'name',
        'multiple' => true,
        'constraints' => array(
            new CustomConstraint(array(
                'message' => 'Application can not be refused.'
            )),
        )
    ));

实体中的属性:

/**
 * @ORM\ManyToMany(targetEntity="RejectReason")
 * @ORM\JoinTable(name="relationship_application_reject_reasons",
 *      joinColumns={@ORM\JoinColumn(name="application_id", referencedColumnName="id", onDelete="CASCADE")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="reject_reason_id", referencedColumnName="id")}
 *      )
 */
private $rejectReasons;

更新

我尝试对其他字符串属性施加约束,我仍然得到NULL

【问题讨论】:

  • 描述一个特定的用例示例,以便更好地了解您想要做什么。
  • 我想创建一个约束来检查实体是否可以执行某些操作。它不应该一直应用于实体,只应用于某些形式。我可以将实体作为选项传递(就像传递消息一样),但这是不好的做法,因为 symfony 应该使用 getObject() 处理这个功能

标签: php symfony validation constraints symfony-2.8


【解决方案1】:

看看ExecutionContextInterface,上面写着:

getObject() 返回当前验证的对象。

如果验证器当前正在验证类约束,则 该类的对象被返回。如果它是一个验证 属性或 getter 约束,属性/getter 所属的对象是 返回。

在其他情况下,返回 null。

如您所见,您必须分配给一个类或一个属性或 getter。否则你会得到null

【讨论】:

  • 它正在验证实体的属性,即 ArrayCollection。查看更新。
  • @IgnasDamunskis 在您的情况下,我建议您创建一个 rejectReasons 表单类型,并添加 data_class 您的实体,并进行级联验证。
【解决方案2】:

如果您正在开发一个类约束验证器,请记得添加 getTargets 方法作为示例:

public function getTargets()
{
    return self::CLASS_CONSTRAINT;
}

如文档中的here 所述

【讨论】:

  • 它是一个属性约束验证器而不是一个类。
  • 嗨@IgnasDamunskis,如果您需要整个对象来验证您需要使用类验证器约束的单个字段
  • 这不是意味着每次实体更新都会验证该类吗?我只在少数情况下需要验证
  • hi @IgnasDamunskis 应该只说明适用范围,试试看会发生什么:)
【解决方案3】:

对于那些使用依赖项本身进行表单验证的人来说,这会有所帮助。 我假设 Symfony 版本是 3.4 或 4.1,并且您的项目中有 symfony/form

构建您的 CustomConstraintValidator

处理具有某种依赖关系的 Symfony 表单验证器的最佳方法是使用 CustomValidators

以上是我用来与他们合作的示例。

假设我们有一个像这样的实体

// src/Entity/myEntity.php
namespace App\Entity;
...

class myEntity
{
    private $id;
    private $name; // string, required
    private $canDrive; // bool, not required (default=false)
    private $driveLicense; // string, not required (default = null)

    public function __construct()
    {
        $this->canDrive = false;
    }
    // getters and setters
}

我们不需要填充$driveLicense(因为该属性不是强制性的),但如果$canDrivefalse更改为true,现在$driveLicense必须有一个值。

$driveLicense 依赖于 $canDrive

要为此构建一个表单并在 FormType 上正确验证 $driveLicense(最佳实践),我们需要构建一个 CustomConstraintValidator。

构建 CanDriveValidator

// src/Validator/Constraints/CanDrive.php
namespace App\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

class CanDrive extends Constraint
{
    public $message = 'invalid_candrive_args'; // I like translators :D
}

翻译文件 - 可选

//src/translators/validators.en.yaml // 
invalid_candrive_args: When "{{ candrivelabel }} " field is checked you must fill "{{ drivelicenselabel }}"

验证器

// src/Validator/Constraints/CanDriveValidator.php
namespace App\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class CanDriveValidator extends ConstraintValidator
{

    /**
     * Checks if the passed value is valid.
     *
     * @param mixed $value The value that should be validated
     * @param Constraint $constraint The constraint for the validation
     */
    public function validate($value, Constraint $constraint)
    {
        $canDriveField = $this->context->getObject(); // the Field using this validator
        $form = $canDriveField->getParent(); // the formType where the Field reside
        $myEntity = $form->getData(); // The Entity mapped by formType                
            
        if ($myEntity->getCanDrive() == true && $myEntity->getDriveLicense() == null) {
            $this->context->buildViolation($constraint->message)
                ->setParameter('{{ candrivelabel }}', 'Can Drive')
                ->setParameter('{{ drivelicenselabel }}', 'Drive License')
                ->addViolation();
        }            
    } 
}

myEntityType 表单

//src/Form/myEntityType.php
namespace App\Form;
use App\Entity\myEntity;
use App\Validator\Constraints\CanDrive;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;


class myEntityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name') 
            ->add('canDrive', CheckBoxType::class, [
                    'required' => false,
                    'constraints' => array(new canDrive()),                    
                    ]                    
                )
            ->add('driveLicense', TextType::class, ['required' => false])
        ;

    }


    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(['data_class' => myEntity::class]);
    }        
}

现在,当使用 myEntityType 表单的调用 isValid() 方法并检查 canDrive 字段并且 driveLicense 为空白时,将在 canDrive 字段上触发 Violation。如果 canDrive 设置为 false(未选中,未提交),则不会发生任何事情,并且即使 driveLicense 为空白,表单也会有效。

【讨论】:

    【解决方案4】:

    答案很简单。写:

    this->context->getRoot()->getData()
    

    你有这个对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-15
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 1970-01-01
      • 1970-01-01
      • 2017-02-26
      • 1970-01-01
      相关资源
      最近更新 更多