1

我的系统中有两个实体:PersonPhone以下代码。

class Person
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $lastName;

    /**
     * @ORM\OneToOne(targetEntity="Phone", cascade={"persist"})
     */
    private $phone;
};

class Phone
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="PhoneType")
     */
    private $type;

    /**
     * @ORM\Column(type="integer")
     */
    private $countryCode;

    /**
     * @ORM\Column(type="integer")
     */
    private $regionCode;

    /**
     * @ORM\Column(type="integer")
     */
    private $number;
};

我还有一个表单来创建和更新一个人(使用电话),所以我有PersonType一个嵌入表单,代表电话(PhoneType)。

我的问题是一个人可以选择拥有电话,但如果该人有电话,则所有电话字段都是必需的。因此,如果用户在所有电话字段上都没有写任何内容,则表示一个没有电话的人,这种情况是有效的。但如果用户填写了至少一个表单字段,则所有其他字段都是必需的。

如果未填写所有电话字段,我尝试通过将电话设置为 null 来采取一种方法,这是setPhonePerson实体中实现的。但是有一个空电话,Symfony 告诉我所有电话字段都是必需的,但没有填写。我相信 Symfony 不会验证手机,因为我认为 Symfony 会直接在个人实体上应用验证。有一个空电话,为什么告诉我所有电话字段都没有填写?

有没有办法做我想做的事(最好不修改我所有的控制器和表单类型,即在实体或验证组件级别)?

编辑:抱歉,有一点没有提到,如果用户填写电话字段,所有电话字段都需要使用不同的验证器单独验证(检查字段是否是格式正确的数字,检查正确的长度等)。但是,如果用户将所有电话字段留空,则应忽略每个字段的验证。

谢谢!

4

5 回答 5

3

我会尝试这种方法:

在您的电话实体中创建其他方法,该方法验证所有字段是否为空或所有字段不为空(这两种情况都是正确的) - 然后返回 true。如果某些字段为空,而某些字段不返回 false。为您的新方法添加一个断言注释 - 这将是您的新约束。

/**
 * @Assert\True(message = "Fill all fields or leave all them blank")
 */

这应该有效。

更多信息请看这里: http ://symfony.com/doc/master/book/validation.html#getters

编辑:

试试这个:

将您的自定义验证方法(检查是否填充任何电话字段)定义为回调(在类的顶部):

 * @Assert\Callback(methods={"checkPhoneFields"})
 */
 class Phone {

接下来,您标记必须使用验证组验证的字段,例如。

/**
 * @ORM\Column(type="string", length=16, groups={"phone_validation"})
 */
private $number;

最后一件事,在您的自定义约束方法中,如果任何字段不为空,您需要打开“phone_validation”组:

public function checkPhoneFields(ExecutionContext $context) {
    if (/* fields are not empty */) {
        $context->getGraphWalker()->walkReference($this, 'phone_validation', $context->getPropertyPath(), true);
    }

这应该有效。

于 2012-08-17T13:59:06.810 回答
2

对于那些路过的人,使用较新版本的 Symfony,您可以:

/**
 *
 * @Assert\Callback()
 */
public function validatePhone(ExecutionContextInterface $context)
{
    if (/* Fields are not empty */)
    {
        $context->validate($this->getPhone(), 'phone', array("phone_validation"));
    }
}
于 2015-09-24T13:15:51.180 回答
0

做这个:

首先在您的电话实体上,将字段声明为“可为空”,如下所示:

/**
 * @ORM\Column(type="integer", nullable=true)
 */
private $countryCode;

这将允许这些字段具有空值。

然后您需要声明一个验证器,该验证器将检查是否没有字段或所有字段都已填写

class Phone {

...
/**
 * @Assert\True(message = "Phone must be empty of fill all fields")
 */
public function isPhoneOK()
{
    // check if no field is null or all of them are
    // return false if these conditions are not met
}
于 2012-08-17T14:14:48.253 回答
0

也可以使用一个非常简单的数据 Transformer 来解决这个问题。

  1. 创建您的电话数据转换器:

    class PhoneTransformer implements DataTransformerInterface
    {
        public function transform($phone)
        {
            if (is_null($phone))
                return new Phone();
    
            return $phone;
        }
    
        public function reverseTransform($phone)
        {
            if (is_null($phone))
                return null;
    
            if (!$phone->getType() && !$phone->getCountryCode() /* ... Test if phone is not valid here */)
                return null;
    
            return $phone;
    }
    
  2. 然后只需在您的 PhoneType 表单中添加此转换器:

    class PhoneType extends AbstractType
    {
        public function buildForm(FormBuilder $builder, array $options)
        {
            $builder
                /* Add fields here :
                ->add( ... )
                */
                ->prependNormTransformer(new PhoneTransformer())
            ;
        }
    }
    

有关如何实现数据转换器的更多详细信息,请参阅http://symfony.com/doc/2.0/cookbook/form/data_transformers.html

于 2012-12-19T18:21:01.733 回答
0

frankie567 的回答对我很有用。对于 symfony >= 3.0:

/**
 *
 * @Assert\Callback()
 */
public function validatePhone(ExecutionContextInterface $context)
{
    if (/* Fields are not empty */)
    {
        $validator = $context->getValidator();

        $validator->inContext($context)
            ->atPath('phone')
            // you can pass custom validation instead of null, like new Assert\Valid()
            ->validate($this->getPhone(), null, array('phone_validation'));   
    }
}
于 2017-10-17T17:14:00.690 回答