How to add validators on the fly in Symfony2? - forms

I've a password form field (not mapped to User password) to be used in a change password form, along with two other (mapped) fields, first and last.
I've to add validators on the fly: if value for password is blank then no validation should occur. Otherwise a new MinLength and MaxLength validators should be added.
Here is what i've done so far: create the repeated password field, add a CallbackValidator and return if $form->getData() is null.
Then, how can i add validators for minimum and maximum length to $field?
$builder = $this->createFormBuilder($user);
$field = $builder->create('new_password', 'repeated', array(
'type' => 'password',
'first_name' => 'Password',
'second_name' => 'Confirm password',
'required' => false,
'property_path' => false // Not mapped to the entity password
));
// Add a callback validator the the password field
$field->addValidator(new Form\CallbackValidator(function($form) {
$data = $form->getData();
if(is_null($data)) return; // Field is blank
// Here password is provided and match confirm, check min = 3 max = 10
}));
// Add fields to the form
$form = $builder
->add('first', 'text', array('required' => false)) // Mapped
->add('last', 'text', array('required' => false)) // Mapped
->add($field) // Not mapped
->getForm();

Oh well, found a solution myself after a few experiments.
I'm going to leave this question unanswered for a couple of days as one can post a better solution, that would be really really welcome :)
In particular, i found the new FormError part redundat, don't know if there is a better way to add the error to the form. And honestly, don't know why new Form\CallbackValidator works while new CallbackValidator won't.
So, don't forget to add use statements like these:
use Symfony\Component\Form as Form, // Mendatory
Symfony\Component\Form\FormInterface,
Symfony\Component\Validator\Constraints\MinLength,
Symfony\Component\Validator\Constraints\MinLengthValidator;
And the callback is:
$validation = function(FormInterface $form) {
// If $data is null then the field was blank, do nothing more
if(is_null($data = $form->getData())) return;
// Create a new MinLengthValidator
$validator = new MinLengthValidator();
// If $data is invalid against the MinLength constraint add the error
if(!$validator->isValid($data, new MinLength(array('limit' => 3)))) :
$template = $validator->getMessageTemplate(); // Default error msg
$parameters = $validator->getMessageParameters(); // Default parameters
// Add the error to the form (to the field "password")
$form->addError(new Form\FormError($template, $parameters));
endif;
};
Well, and this is the part i can't understand (why i'm forced to prefix with Form), but it's fine:
$builder->get('password')->addValidator(new Form\CallbackValidator($validation));

addValidator was deprecated and completly removed since Symfony 2.3.
You can do that by listening to the POST_SUBMIT event
$builder->addEventListener(FormEvents::POST_SUBMIT, function ($event) {
$data = $event->getData();
$form = $event->getForm();
if (null === $data) {
return;
}
if ("Your logic here") {
$form->get('new_password')->addError(new FormError());
}
});

Related

understanding Zend\Form\Element\Date

I have two issues while using the Zend-Form date element.
First: field binding
The edit action within my controller doesn't fillin an existing date. For example birthday. The field is just empty. (with an element type text, there is no problem).
Here how I instanciated the field:
$this->add([
'name' => 'geburtstag',
'type' => 'date',
'options' => [
'label' => 'Geburtstag:',
'format' => 'dd/mm/yyyy',
],
]);
And here my controller action.
public function addAction()
{
$form = new AnsprechpartnerForm(NULL, $this->db);
$form->get('submit')->setValue('save');
$request = $this->getRequest();
if (! $request->isPost()) {
return ['form' => $form];
}
$ansprechpartner = new Ansprechpartner();
$form->setInputFilter($ansprechpartner->getInputFilter());
$form->setData($request->getPost());
if (! $form->isValid()) {
return ['form' => $form];
}
$ansprechpartner->exchangeArray($form->getData());
$this->ansprechpartnerTable->saveAnsprechpartner($ansprechpartner);
return $this->redirect()->toRoute('ansprechpartner');
}
No inputFilter at the moment, I tried with and without.
Second: validation
I have trouble filling in dates. While I don't use any filters for this field, I would expect, I could fill any date in.
Interesting I get the message double.
I solved it.
The date element expects the format y-m-d. Now I gave it directly to the field after binding the form. The format in the field is now also korrekt.
$form->bind($notizen);
$form->get('submit')->setAttribute('value', 'edit');
$filter = new \Zend\Filter\DateTimeFormatter();
$filter->setFormat('Y-m-d');
$dat = $filter->filter($notizen->datum);
$form->get('datum')->setValue($dat);
Could be more convenient I guess.

How to disable filter of a field in Zend Framework 2 in the controller?

Form to add/edit user I get from service manager with already installed filter, which is the test password. But this password is not needed when the user is edited. Can I somehow disabled password field validation in the controller?
In the getServiceConfig function of the module:
// ....
'UserCRUDFilter' => function($sm)
{
return new \Users\Form\UserCRUDFilter();
},
'UserCRUDForm' => function($sm, $param, $param1)
{
$form = new \Users\Form\UserCRUDForm();
$form->setInputFilter($sm->get('UserCRUDFilter'));
return $form;
},
// ....
In the controller I first of all getting a form object from service manager:
$form = $this->getServiceLocator()->get('UserCRUDForm');
Then disable user password validation and requirements, when user is edited and password not specified:
if ($user_id > 0 && $this->request->getPost('password') == '') {
$form->.... // Someway gained access to the filter class and change the password field validation
}
And after this i make a validation:
$form->isValid();
I found it!
// If user is editted - clear password requirement
if ($user_id > 0) {
$form->getInputFilter()->get('password')->setRequired(false);
$form->getInputFilter()->get('confirm_password')->setRequired(false);
}
This lines is disables requirement of input form fields :)
if you like to set all validators by yourself, call inside your form class
$this->setUseInputFilterDefaults(false);
to disable auto element validations/filter added from zend.
if you like to remove filter from elements call in your controller after your form object this
$form->getInputFilter()->remove('InputFilterName');
$form->get('password')->removeValidator('VALIDATOR_NAME'); should do the trick.
Note that you may have to iterate trough the Validatorchain when using Fieldsets.
$inputFilter->add(array(
'name' => 'password',
'required' => true,
'allow_empty' => true,
));
And on ModeleTable: saveModule:
public function saveAlbum(Album $album)
{
$data = array(
'name' => $album->name,
);
if (isset($album->password)){
$data['password'] = $album->password;
}

Drupal 6 - ignore required form field

I need to ignore the validation of two form field while creating a user in Drupal 6 but I don't know at all how to do :
$userinfo = array(
'name' => $login,
'init' => $mail,
'mail' => $mail,
'pass' => $password,
'status' => 1,
'lastname' => "", //how to ignore those required fields that invalidate the form
'surname' => "" //how to ignore those required fields that invalidate the form
);
// register a new user
$form_state = array();
$form_state['values'] = $userinfo;
drupal_execute('user_register', $form_state);
$errors = form_get_errors(); // getting 2 required field errors
Note that I can't supress the "required" property as it is used elsewhere in a more "complex" form.
Thanks
I haven't got a D6 site handy to test this on but I think it'll work...
Since drupal_execute() pushes you through the whole form build process you can take advantage of hook_form_alter() to remove the required status, but only in a context you pass along in the $form_state. For example
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'user_register' && !empty($form_state['custom_execution'])) {
$form['lastname']['#required'] = FALSE;
// etc...
}
}
...
$form_state = array();
$form_state['values'] = $userinfo;
$form_state['custom_execution'] = TRUE;
drupal_execute('user_register', $form_state);
Can't you use hook_form_alter to supress the "required" property, only when the from is not used in its "complex" form?
For instance, if you know what paths the "complex" form is used, you can check if that paths is being served with arg.
Better checks may be available...

Duplicate Validation on Combined Fields in zend form

Hi there I have a table in which combination of three fields is unique. I want to put the check of duplication on this combination. Table looks like
I know how to validate single field, But how to validate the combination is not know. To validate one field I use the following function
public function isValid($data) {
// Options for name field validation
$options = array(
'adapter' => Zend_Db_Table::getDefaultAdapter(),
'table' => 'currencies',
'field' => 'name',
'message'=> ('this currency name already exists in our DB'),
);
// Exclude if a id is given (edit action)
if (isset($data['id'])) {
$options['exclude'] = array('field' => 'id', 'value' => $data['id']);
}
// Validate that name is not already in use
$this->getElement('name')
->addValidator('Db_NoRecordExists', false, $options
);
return parent::isValid($data);
}
Will any body guide me how can I validate duplication on combined fields?
There is no ready to use validator for this, as far as I know. You have either to write your own, or do a check with SQL-query with three conditions (one for each field).
you have to Apply a validation on name element of zend form.
Here is code for add validation on name field.
$name->addValidator(
'Db_NoRecordExists',
true,
array(
'table' => 'currencies',
'field' => 'name',
'messages' => array( "recordFound" => "This Currency Name already exists in our DB") ,
)
);
And you must set required true.

Validate subform that's not connected to entity in Symfony 2

I've got a form in Symfony2 that's not connected to any entity. It has a child form, of which 1..n instances can be added dynamically on the front-end.
$builder
//car data
->add('cars', 'collection', array(
'label' => ' ',
'type' => new CarLeasingType(),
'allow_add' => true,
'prototype' => true,
))
The parent form has it's validation to validate other fields that are in the form.
public function getDefaultOptions(array $options)
{
$collectionConstraint = new Collection(array(
'fields' => array(
//some fields an their validation
),
'allowExtraFields' => true,
));
return array('validation_constraint' => $collectionConstraint);
}
The child form (of type CarLeasingType) has it's own validation. My problem now has two levels:
I had to set 'allowExtraFields' to true in parent form validation constraint, otherwise I got a message like The fields 0, 1 were not expected
The validation constraint in the child form is not executed at all.
To explain why the cars fields from the subform are identified as 0 and 1 here is the JavaScript function I use to generate the subform dynamically from the data-prototype attribute:
function add_dynamic_field(holderId) {
var collectionHolder = $('#' + holderId);
if (0 === collectionHolder.length) return false;
var prototype = collectionHolder.attr('data-prototype');
form = prototype.replace(/<label class=" required">\$\$name\$\$<\/label>/, '');
form = form.replace(/\$\$name\$\$/g, collectionHolder.children().length);
collectionHolder.append(form);
}
How can I validate also each of the subforms added dynamically?
Perhaps something along these lines might help:
public function somexAction()
{
//get objects through the $form object
//get validator service
$validator = $this->get('validator');
//validate objects manually
foreach object as obj
$errors = $validator->validate($obj);
if (count($errors) > 0) {
//...
} else {
//....
}
}
Basically, it means taking advantage of the validator service.
Taken from http://symfony.com/doc/current/book/validation.html
For more info on the validator methods/etc., check out the api.