我的系统中有两个实体:Person
和Phone
,如下代码所示。
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
)。
我的问题是,一个人可以选择手机,但如果此人有手机,则需要所有手机字段。因此,如果用户在所有电话字段上都没有写任何内容,则表示没有电话的人,这种情况有效。但是,如果用户填写至少一个表单字段,则所有其他字段都是必需的。
如果未填写所有电话字段,我会尝试将电话设置为空,这是在setPhone
实体的Person
上实施的。但是有一个空电话,Symfony告诉我所有电话领域都是必需的,但没有填写。
我相信Symfony不会验证手机,因为我认为Symfony会直接在人员实体上应用验证。有了一部空电话,为什么告诉我所有电话领域都没有填写?
有没有办法做我想要的事情(最好不要修改我的所有控制器和表单类型,即在实体或验证组件级别)?
编辑抱歉,有一些未提及的内容,如果用户填写手机字段,则需要使用不同的验证码单独验证所有电话字段(检查字段是否格式正确,检查正确的长度等)。但是如果用户将所有电话字段留空,则应忽略每个字段的验证。
谢谢!
答案 0 :(得分:3)
我会尝试这种方法:
在您的Phone实体中创建另一个方法,该方法验证所有字段是否为空或所有字段都不为空(这两种情况都是正确的) - 然后返回true。如果某些字段为null,则某些字段不返回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);
}
这应该有用。
答案 1 :(得分:2)
对于那些路过的人,可以使用较新版本的Symfony:
/**
*
* @Assert\Callback()
*/
public function validatePhone(ExecutionContextInterface $context)
{
if (/* Fields are not empty */)
{
$context->validate($this->getPhone(), 'phone', array("phone_validation"));
}
}
答案 2 :(得分: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
}
答案 3 :(得分:0)
也可以使用非常简单的数据Transformer来解决这个问题。
创建手机数据转换器:
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;
}
然后只需在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。
答案 4 :(得分: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'));
}
}