Reputation: 1227
I have two entities in my system: Person
and Phone
as the following code.
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;
};
I also have a form to create and update a person (with the phone), so I have a PersonType
that have a embed form representing a phone (PhoneType
).
My problem is that a person can has optionally a phone, but if the person has a phone, all the phone fields are required. So, if user write nothing on all phone fields, this represent a person without phone and this case is valid. But if the user fills at least one form field, all other fields are required.
I try to take an approach by setting the phone on null if all phone fields are not filled, this was implemented on setPhone
in Person
entity. But having a null phone, Symfony tell me that all phone fields are required but are not filled.
I believe that Symfony will not validate the phone because I suppose that Symfony will apply the validation directly on person entity. Having a null phone, why tell me that all phone fields are not filled?
Is there a way to do what I want (preferably without modify all my controllers and form types, that is, at entity or validation component level)?
EDIT: Sorry, there is something not mentioned, if user fill a phone field, all phone fields need to be validated separately with different validators (to check if a field is a well formed number, to check correct length, etc). But if user leaves empty all phone fields, the per-field validation should be ignored.
Thanks!
Upvotes: 1
Views: 3204
Reputation: 736
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'));
}
}
Upvotes: 0
Reputation: 1760
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"));
}
}
Upvotes: 2
Reputation: 1
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.
Upvotes: 0
Reputation: 11364
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.
Upvotes: 3
Reputation: 11351
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
}
Upvotes: 0