Reputation: 4704
I'm a Symfony noob trying unsuccessfully to visualize how best to validate a form field based on either it or a different field. The case: a form will solicit either a date of birth or an age. If the dob is entered, age is ignored. If age is entered and dob is empty, the dob is said to be today's date less age in years. If neither is entered a validation error is thrown. I've accomplished this with Smarty validation; as a learning exercise I'm trying to reproduce the application in Symfony.
I've looked at this solution where both fields are properties of an entity. In my case age is not, only dob. So it's not clear to me how to apply that solution. I'd greatly appreciate pointers.
Thanks.
George PS: (edited: dreck removed) PPS: (edited: removed to make room for nearly working version) Form:
// src\Mana\AdminBundle\Resources\views\Form\Type\NewClientType.php
namespace Mana\AdminBundle\Form\Type;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Mana\AdminBundle\Validator\Constraints;
class NewClientType extends AbstractType {
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array('validation_groups' => 'client_new',
'validation_constraint' => new DOBorAge(),
));
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('fname', null, array('required' => false));
$builder->add('sname', null, array('required' => false));
$builder->add('dob', 'birthday', array('widget' => 'single_text', 'required' => false));
$builder->add('age', null, array('mapped' => false, 'required' => false));
}
public function getName() {
return 'client_new';
}
}
services:
services:
client_new:
class: Mana\AdminBundle\Validator\Constraints\DOBorAgeValidator
scope: request
tags:
- { name: validator.constraint_validator, alias: dobage_validator}
Validators:
// src\Mana\AdminBundle\Form\Type\DOBorAge.php
namespace Mana\AdminBundle\Form\Type;
use Mana\AdminBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
class DOBorAge extends Constraint {
public $message = 'Either a date of birth or age must be present';
public function validatedBy() {
return 'dobage_validator';
}
public function getTargets() {
return Constraint::CLASS_CONSTRAINT;
}
}
and
// src\Mana\AdminBundle\Validator\Constraints\DOBorAgeValidator.php
namespace Mana\AdminBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class DOBorAgeValidator extends ConstraintValidator {
protected $request;
public function __construct(Request $request) {
$this->request = $request;
}
public function validate($value, Constraint $constraint) {
var_dump($this->request->request->get('client'));
die();
return true;
}
}
Upvotes: 1
Views: 2914
Reputation: 13891
I think that the best way to manage this kind of validation is to add a customized validation constraint to your form.
Just add a class that extend Symfony\Component\Validator\Constraint
and override the validatedBy()
method. You can then specify a customized validator that you've to create so that it contains all the logic of your form validation.
This customized validator should extend Symfony\Component\Validator\ConstraintValidator
class and implement the isValid()
method for Symfony 2.0.x or validate()
method for Symfony 2.1.x.
You can then Check your values, compare them and do whatever you want inside this method and add eventually add violations if one or many of your validation rules aren't respected.
Also check Symfony2 validation based on two fields.
Upvotes: 1
Reputation: 4704
A Symfony-esque solution: a single form field that takes either a date or an age, then transform the entry into a date. (Now, if I could only turn this into a custom field...)
namespace Mana\AdminBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Mana\AdminBundle\Form\DataTransformer\AgeToDOB;
class NewClientType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$transformer = new AgeToDOB();
$builder->add('fname', null, array('required' => false,
'invalid_message' => 'First name not be blank',));
$builder->add('sname', null, array('required' => false,
'invalid_message' => 'Last name not be blank',));
$builder->add(
$builder->create('dob', 'text', array('required' => false,
))->addModelTransformer($transformer));
}
public function getName() {
return 'client_new';
}
}
and the transformer:
namespace Mana\AdminBundle\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Mana\AdminBundle\Entity\Client;
class AgeToDOB implements DataTransformerInterface {
public function reverseTransform($dob) {
if (null == $dob) {
return '';
}
if ((substr_count($dob, '/') == 2 && strtotime($dob))) {
$date = new \DateTime($dob);
return date_format($date, 'Y-m-d');
}
if (is_numeric($dob)) {
$date = new \DateTime();
$interval = 'P' . $dob . 'Y';
$date->sub(new \DateInterval($interval));
return date_format($date, 'Y-m-d');
}
}
public function transform($client) {
if (null == $client) {
return '';
}
if (is_object($client)) {
$dob = $client->getDob();
// date: test for two / characters
if ((substr_count($dob, '/') == 2 && strtotime($dob))) {
$date = new \DateTime($dob);
return date_format($date, 'm/d/Y');
}
if (is_numeric($dob)) {
$date = new \DateTime();
$interval = 'P' . $dob . 'Y';
$date->sub(new \DateInterval($interval));
return date_format($date, 'm/d/Y');
}
}
}
}
Upvotes: 1