I have two entities in my system: Person
and Phone
as the following code.
class Person
{
/**
* @ORM\\Id
* @ORM\\Colum
Do this:
First on your phone entity, declare the fields as "nullable" like this:
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $countryCode;
This will allow these fields to have a null value.
Then you need to declare a validator that will check if either none of the fields or all of them are filled
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
}
It is also possible to use a very simple data Transformer to solve this problem.
Create your Phone data 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;
}
Then simply prepend this transformer in your PhoneType form :
class PhoneType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
/* Add fields here :
->add( ... )
*/
->prependNormTransformer(new PhoneTransformer())
;
}
}
See http://symfony.com/doc/2.0/cookbook/form/data_transformers.html for more details on how implement data transformers.
I would try this method:
create additional method in your Phone entity which validates if all fields are null or all fields are not null (these two cases are correct) - and then return true. If some fields are null and some aren't return false. Add an assert annotation to your new method - this will be your new constraint.
/**
* @Assert\True(message = "Fill all fields or leave all them blank")
*/
And this should work.
For more information look here: http://symfony.com/doc/master/book/validation.html#getters
edit:
Try this one:
define your custom validation method (this one which check if any of phone fields is filled) as Callback (at the top of the class):
* @Assert\Callback(methods={"checkPhoneFields"})
*/
class Phone {
Next you mark field wich have to be validated with validation group, eg.
/**
* @ORM\Column(type="string", length=16, groups={"phone_validation"})
*/
private $number;
And the last thing, in your custom constraint method you need to switch on "phone_validation" group if any of field isn't empty:
public function checkPhoneFields(ExecutionContext $context) {
if (/* fields are not empty */) {
$context->getGraphWalker()->walkReference($this, 'phone_validation', $context->getPropertyPath(), true);
}
And that should work.
frankie567's answer was useful to me. For 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'));
}
}
For those passing by, with newer versions of Symfony you can do :
/**
*
* @Assert\Callback()
*/
public function validatePhone(ExecutionContextInterface $context)
{
if (/* Fields are not empty */)
{
$context->validate($this->getPhone(), 'phone', array("phone_validation"));
}
}