Closed zd-dalibor closed 11 years ago
Provide us with code snippet please. It works on my end.
Test for this has been implemented. You may update this bundle
composer.phar update apy/jsfv-bundle
and run the test as described here
I have class defined like this:
namespace ...
use Symfony\Component\Validator\Constraints as Assert;
class UserData
{
/**
* @var string
*
* @Assert\NotBlank()
* @Assert\Email()
*/
protected $email;
/**
* @var string
*
* @Assert\NotBlank()
*/
protected $password;
/**
* @var string
*
* @Assert\NotBlank()
*/
protected $username;
/**
* @var string
*/
protected $geopcCountry;
/**
* @var string
*/
protected $geopcLanguage;
/**
* @var integer
*/
protected $geopcId;
/**
* @var \DateTime
*
* @Assert\NotBlank()
*/
protected $birthday;
/**
* @var bool
*
* @Assert\NotBlank()
*/
protected $gender;
...
}
end form type defined like this:
namespace ...
use Symfony\Component\Form\AbstractType;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use EWZ\Bundle\RecaptchaBundle\Validator\Constraints\True;
class UserDataType extends AbstractType
{
protected $help = array();
protected $logger;
function __construct()
{
$this->help = array(
'email' => implode(' ', array(
'Your email will not be shown publicly.',
'You can change your privacy settings at any time.'
)),
'password' => 'Minimum of 6 characters long.',
'username' => implode(' ', array(
'Please enter a username between 6 and 25 characters long.',
'It can only contain letters A-Z or numbers 0-9; no spaces.',
'Your public profile will be: http://zugme.com/USERNAME'
)),
'gender' => implode(' ', array(
'Your date of birth and gender will not be shown publicly.',
'You can change your privacy settings at any time.',
'For security reasons, you might be asked to confirm your date of birth and gender.'
))
);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', 'text', array(
'label' => 'E-mail address:',
'help' => $this->help['email'],
))
->add('password', 'repeated', array(
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'options' => array('required' => true),
'first_options' => array('label' => 'Password:', 'help' => $this->help['password']),
'second_options' => array('label' => 'Confirm Password:'),
))
->add('username', 'text', array(
'label' => 'Username:',
'help' => $this->help['username'],
))
->add('geopcCountry', 'hidden')
->add('geopcLanguage', 'hidden')
->add('geopcId', 'hidden')
->add('country', 'entity', array(
'label' => 'Country/Region:',
'empty_value' => '',
'class' => 'ZugmeRepositoryBundle:CountryCode',
'property' => 'country',
'expanded' => false,
'multiple' => false,
'property_path' => false,
))
->add('zip', 'text', array(
'label' => 'Postal Code:',
'property_path' => false
))
->add('birthday', 'birthday', array(
'label' => 'Date of Birth:',
'widget' => 'choice',
'format' => 'yyyy MMMM dd',
'empty_value' => '',
))
->add('gender', 'choice', array(
'label' => 'Gender:',
'choices' => array(
'Male',
'Female',
),
'expanded' => true,
'multiple' => false,
'help' => $this->help['gender']
))
->add('recaptcha', 'ewz_recaptcha', array(
'label' => 'Security code:',
'attr' => array(
'options' => array(
'theme' => 'clean',
'lang' => 'en'
)
),
'property_path' => false,
'constraints' => array(
new True()
),
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => '...\UserData',
));
}
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
public function getName()
{
return 'user_data';
}
}
and this is what this bundle generate for js validation script:
/**
* This file is part of the JsFormValidationBundle.
*
* (c) Abhoryo <abhoryo@free.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var jsfv = new function () {
function getComputeMessage(key, placeholders, number) {
ExposeTranslation.placeHolderPrefix = '{{ ';
ExposeTranslation.placeHolderSuffix = ' }}';
// Default translations
if (!ExposeTranslation.has('validators:'+key)) {
ExposeTranslation.add('validators:'+key, key);
}
return ExposeTranslation.get('validators:'+key, placeholders, number);
}
function isNotDefined(value) {
return (typeof(value) == 'undefined' || null === value || '' === value);
}
function checkError(field, checkFunction, parameters, value) {
field = jsfv.id(field);
// Remove old errors of the field
jsfv.removeErrors(field); // Check the value
errorMessage = checkFunction((value === undefined ? field : value), parameters);
/*// */
if (errorMessage != true) {
jsfv.addError(field, errorMessage);
return false;
}
return true;
}
function Repeated(field, params)
{
var value = field && field.nodeName ? $(field).val() : field;
first = document.getElementById(params.first_name).value;
second = document.getElementById(params.second_name).value;
if (first !== second) {
return getComputeMessage(params.invalid_message, params.invalid_message_parameters);
}
return true;
}
return {
id: function (id) {
return document.getElementById(id);
},
removeErrors: function (field) {
$(field).siblings('ul.error_list').remove();
},
addError: function (field, errorMessage) {
// Add errors block
field = $(field);
if (field.siblings('ul.error_list').length == 0) {
field.before('<ul class="error_list"></ul>');
}
// Add error
field.prev().filter('ul').append('<li>'+errorMessage+'</li>');
},
onEvent: function (field, eventType, handler) {
if (typeof(field) == 'string') {
field = jsfv.id(field);
}
$(field).bind(eventType, handler);
},
check_user_data_password_second: function() {
var gv;
result = true;
result = result && checkError('user_data_password_second', Repeated, {first_name: 'user_data_password_first', second_name: 'user_data_password_second', invalid_message: 'The password fields must match.', invalid_message_parameters: null} );
return result;
},
onReady: function() {
// On submit checks
var form = jsfv.id('user_data');
// Form exists ?
if (form) {
// Get the form
if ( form.nodeName.toLowerCase() != 'form') {
form = jsfv.id('ma_form__token').form;
}
jsfv.onEvent(form, 'submit', function() {
var gv, submitForm = true;
submitForm = jsfv.check_user_data_password_second() && submitForm;
return submitForm;
});
}
// On blur checks
jsfv.onEvent('user_data_password_second', 'blur', jsfv.check_user_data_password_second);
}
};
}
$(jsfv.onReady);
As you can see the js validation bundle is recognize only repeated field and nothing else (required, email etc. look in UserData class).
I think there is a problem when the bundle retreive the entity of the form.
// FormValidationScriptGenerator.php - Line 201
$formViewValue = $formView->get('value');
I don't know how you have build your form in your controller. Can you debug $formViewValue variable and see what entity is used by the bundle ?
I think that the bundle can't handle multiple entities in the same form builder.
What about phpunit test? Has it passed? I looked in your code and your constraints should work. However, I do not see your controller. Here in the TestBundle you can found simple example:
$formView->get('value') return null until request is not bound to form eq.
$form = $this->createForm(new UserDataType());
$formView = $form->createView();
$formViewValue = $formView->get('value'); // $formViewValue is null
$request = $this->getRequest();
$form = $this->createForm(new UserDataType());
if ($request->getMethod() == 'POST') {
$form->bind($request);
$formView = $form->createView();
$formViewValue = $formView->get('value'); // $formViewValue is typeof ...\UserData
}
Try to use
$user = new UserData();
//...
$form = $this->createForm(new UserDataType(), $user);
This is the cause.
Good catch.
The purpose of symfony form types is to use createForm function of controller without supplying instance of data carrier class (second parameter). that instance can be got with $form->getData();
You should add this in doc:
"If you wont this bundle working properly you must supply second parameter to createForm controller function."
I think we should consider an possibility to fetch Entity class name from the data_class property of the FormType instance.
Yeah data_class is better.
It has been fixed. composer.phar update apy/jsfv-bundle
This validation bundle do not read constraints from php anotations in symfony 2.1.