Recaptcha google with EWZRecaptchaBundle for Symfony - forms

I want to have a recaptcha system to my contact form symfony. For that I use a EWZRecaptchaBundle. But I try lot of stuff tricks for running recaptcha but my form submit run without testing validation recaptcha widget (invisible and visible)
Can you help me to run recaptcha correctly. My submit form run without deal with recaptcha but I have the widget display correctly.
config.yml
ewz_recaptcha:
public_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
private_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
locale_key: %kernel.default_locale%
locale_from_request: false
enabled: true
verify_host: true
ajax: false
ContactType
->add('recaptcha', EWZRecaptchaType::class, array(
'attr' => array(
'options' => array(
'theme' => 'light',
'type' => 'image',
'size' => 'invisible',
'defer' => true,
'async' => true,
'callback' => 'onReCaptchaSuccess',
'bind' => 'contact_submit',
)
),
'mapped' => false,
'constraints' => array(
new RecaptchaTrue()
)
)
)
// ->add('recaptcha', EWZRecaptchaType::class)
->add('submit', SubmitType::class, [
'label' => 'form.submit.send',
'attr' => ['class' => 'btn1 form_recaptcha_submit', 'id' => 'contact_submit']
])
Twig template
{{ form_widget(form.recaptcha, { 'attr': {
'options' : {
'theme': 'light',
'type': 'image',
'size': 'invisible'
},
} }) }}
contact (entity)
I have my field recaptcha
private $recaptcha;
I have the widget recaptcha google which display correctly but my submit form don't work with this. never.
I have registered my domain on google website recaptcha

You need to define the validation in your form (it is also possible to validate in the entity class). Also in my case I did not create a field in my eneity. I prefered to use what we call a "non mapped" field. To use a non mapped field you just need to use 'mapped' => false, in your contactType
I show you below the code I used:
My ContactType:
->add('recaptcha', EWZRecaptchaType::class, array(
'attr' => array(
'options' => array(
'theme' => 'light',
'type' => 'image',
'size' => 'normal',
'defer' => true,
'async' => true,
)
)
,
'mapped' => false,
'constraints' => array(
new RecaptchaTrue()
)
))
I give you my config.yml so you can see I don't need that much options to be defined to make recaptcha works:
ewz_recaptcha:
public_key: xxxx
private_key: xxxx
# Not needed as "%kernel.default_locale%" is the default value for the locale key
locale_key: %kernel.default_locale%
locale_from_request: true
edit: to display the recaptcha widget with twig in my template, I just use {{ form_end(form) }} and the recaptcha widget is on top of the submit button.
edit 2: You don't need to do any validation in your controller but this one:
if ($contactForm->isSubmitted() && $contactForm->isValid())
{
//your logic
}

Related

Validation error "This value should not be blank" when submitting a form on production website

I'm developing a website using php 7.4, symfony 5.4 and twig. This website is deployed on several servers.
On one of the servers (RedHat), a form cannot be submitted. I get the following error 4 times : "This value should not be blank.".
The messages appear on top of the form and aren't attached to a particular field.
I can't reproduce this error on another server, nor on my development environment...
The problem might comes from a validator but I'm not sure whether it's a symfony or a doctrine error.
The POST data is identical on production server and dev environment :
report_selection[iFrame]: 1
report_selection[dteFrom]: 2023-01-30 07:00
report_selection[dteTo]: 2023-01-31 07:00
report_selection[reportType]: 1
report_selection[size]: 200
report_selection[product]: 1
report_selection[submit]:
I assume that the empty field submit is not a problem since other forms work fine while having the same field empty.
The database structure is the same on all servers.
Here is the form's code :
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$bDisplaySize = $options['bDisplaySize'];
$bDisplayReportType = $options['bDisplayReportType'];
$bDisplayProduct = $options['bDisplayProduct'];
$defaultValue = $options['defaultValue'];
$em = $options['entity_manager'];
list($H, $m) = explode(":", $iShiftStart);
$initialFromDate = (new DateTime())->modify('-'.$H.' hour');
$initialFromDate = $initialFromDate->modify('-1 day');
$initialFromDate->setTime((int)$iShiftStart, (int)$m, 0);
$initialToDate = clone $initialFromDate;
$initialToDate = $initialToDate->modify('+1 day');
$builder->add(
'iFrame',
ChoiceType::class,
array(
'label' => 'master.preselection',
'choices' => [
'master.yesterday' => false,
'master.today' => false,
'master.thisWeek' => false,
'master.lastWeek' => false,
'master.thisMonth' => false,
'master.lastMonth' => false,
'master.memomryDate' => false,
],
'attr' => ['onchange' => 'refreshPreselectedChoices()'],
'choice_attr' => [
'master.yesterday' => [],
'master.today' => ['selected' => 'selected'],
'master.thisWeek' => [],
'master.lastWeek' => [],
'master.thisMonth' => [],
'master.lastMonth' => [],
'master.memomryDate' => ['disabled' => true],
],
)
);
$builder->add(
'dteFrom',
TextType::class,
array(
'label' => 'form.from',
'data' => $initialFromDate->format('Y-m-d H:i'),
'attr' => array(
'style' => 'width:150px;',
'oninput' => 'dteFromToCustom()',
'onchange' => 'dteFromToCustom()',
),
)
);
$builder->add(
'dteTo',
TextType::class,
array(
'label' => 'form.to',
'data' => $initialToDate->format('Y-m-d H:i'),
'attr' => array(
'label' => 'form.to',
'style' => 'width:150px;',
'oninput' => 'dteFromToCustom()',
'onchange' => 'dteFromToCustom()',
),
)
);
if ($bDisplayReportType) {
$builder->add(
'reportType',
ChoiceType::class,
array(
'label' => 'summaryReport.data',
'choices' => array(
'summaryReport.type1' => '1',
'summaryReport.type2' => '2',
),
)
);
}
if ($bDisplaySize) {
$builder->add(
'size',
EntityType::class,
array(
'class' => ProductsSizeSpecs::class,
'choice_label' => 'rSize',
'choice_value' => 'rSize',
'placeholder' => '',
'label' => 'form.size',
'required' => false,
'mapped' => false,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('e')
->groupBy('e.rSize')
->orderBy('e.rSize', 'ASC');
},
)
);
}
if ($bDisplayProduct) {
$builder->add(
'product',
EntityType::class,
array(
'class' => Products::class,
'choice_label' => 'sNumber',
'choice_value' => 'sNumber',
'placeholder' => '',
'label' => 'master.product',
'required' => false,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('e')
->groupBy('e.sNumber')
->orderBy('e.sNumber', 'ASC');
},
)
);
}
$builder->add(
'submit',
SubmitType::class,
array(
'label' => 'form.submit',
'attr' => array('class' => 'btn btn-primary'),
)
);
}
Other forms use the exact same code with more or less options.
I search a way to debug this on the production server (list/dump of 'blank' fields?).
Any hint will be appreciated, thanks !
Indeed I had some #Assert\NotBlank on several columns of an Entity.
Why the error was only on this server :
An instance (db record) of this Entity was NULL on those columns (which is an anormal behavior).
All the instances where retrieved to populate the form's dropdowns (as 'default' data).
It looks like the validator is checking the submitted 'data' AND those 'default' values since they are part of the form.
There were 4 asserted columns, so that's why I had 4 errors messages.
What I've done to find this out :
Added a dump($this->form->getErrors()) instruction on the callback processing the submitted form. It displayed the 4 entity's columns giving me hard time.
Went into db to see the corrupted record, and deleted it.
To prevent this in the future I might change the default values of these columns from NULL to something else, a basic string or a 0 value, and search the process that led to this corrupted record in db.
Thanks for your hints guys !

Radio button: input was not found in the haystack?

Whenever I submit the form I get this message:
The input was not found in the haystack.
This is for the shipping-method element (radio button). Can't figure out what it means, the POST data for that element is not null.
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
// Some other basic filters
$inputFilter->add(array(
'name' => 'shipping-method',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim')
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'max' => 20,
),
),
array(
'name' => 'Db\RecordExists',
'options' => array(
'table' => 'shipping',
'field' => 'shipping_method',
'adapter' => $this->dbAdapter
)
),
),
));
$inputFilter->get('shipping-address-2')->setRequired(false);
$inputFilter->get('shipping-address-3')->setRequired(false);
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
I only keep finding solutions for <select>.
Here's the sample POST data:
object(Zend\Stdlib\Parameters)#143 (1) {
["storage":"ArrayObject":private] => array(9) {
["shipping-name"] => string(4) "TEST"
["shipping-address-1"] => string(4) "test"
["shipping-address-2"] => string(0) ""
["shipping-address-3"] => string(0) ""
["shipping-city"] => string(4) "TEST"
["shipping-state"] => string(4) "TEST"
["shipping-country"] => string(4) "TEST"
["shipping-method"] => string(6) "Ground"
["submit-cart-shipping"] => string(0) ""
}
}
UPDATE:
form.phtml
<div class="form-group">
<?= $this->formRow($form->get('shipping-method')); ?>
<?= $this->formRadio($form->get('shipping-method')
->setValueOptions(array(
'Ground' => 'Ground',
'Expedited' => 'Expedited'))
->setDisableInArrayValidator(true)); ?>
</div>
ShippingForm.php
$this->add(array(
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => array(
'label' => 'Shipping Method',
'label_attributes' => array(
'class' => 'lbl-shipping-method'
),
)
));
The problem lies with when you use the setValueOptions() and the setDisableInArrayValidator(). You should do this earlier within your code as it is never set before validating your form and so the inputfilter still contain the defaults as the InArray validator. As after validation, which checks the inputfilter, you set different options for the shipping_methods.
You should move the setValueOptions() and the setDisableInArrayValidator() before the $form->isValid(). Either by setting the right options within the form itsself or doing this in the controller. Best way is to keep all of the options in one place and doing it inside the form class.
$this->add([
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => [
'value_options' => [
'Ground' => 'Ground',
'Expedited' => 'Expedited'
],
'disable_inarray_validator' => true,
'label' => 'Shipping Method',
'label_attributes' => [
'class' => 'lbl-shipping-method',
],
],
]);
Another small detail you might want to change is setting the value options. They are now hardcoded but your inputfilter is checking against database records whether they exist or not. Populate the value options with the database records. If the code still contains old methods but the database has a few new ones, they are not in sync.
class ShippingForm extends Form
{
private $dbAdapter;
public function __construct(AdapterInterface $dbAdapter, $name = 'shipping-form', $options = [])
{
parent::__construct($name, $options)
// inject the databaseAdapter into your form
$this->dbAdapter = $dbAdapter;
}
public function init()
{
// adding form elements to the form
// we use the init method to add form elements as from this point
// we also have access to custom form elements which the constructor doesn't
$this->add([
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => [
'value_options' => $this->getDbValueOptions(),
'disable_inarray_validator' => true,
'label' => 'Shipping Method',
'label_attributes' => [
'class' => 'lbl-shipping-method',
],
],
]);
}
private function getDbValueOptions()
{
$statement = $this->dbAdapter->query('SELECT shipping_method FROM shipping');
$rows = $statement->execute();
$valueOptions = [];
foreach ($rows as $row) {
$valueOptions[$row['shipping_method']] = $row['shipping_method'];
}
return $valueOptions;
}
}
Just had this happen yesterday.
The select and multi select ZF2+ elements have a built in in_array validator.
Remember filters occur before validators.
You may be doing too much here -- it is very rare to need to filter or add validators ot select and multi select form elements in ZF2 forms. The built in element validator is robust, ZF does a lot of work for us.
Try removing both filter and validator for the element, such as:
$inputFilter->add(array(
'name' => 'shipping-method',
'required' => true,
));
There is another edge case that I have seen: changing the select element's valueOptions somewhere in the controller (or view) resulting in different valueOptions used in view vs form validation (in our case it was replacing the element with a new one before validation).
I think your problem lies in the fact you are adding your value options after the InArray validator has been set, hence the validator has no haystack.
Try this
$this->add(array(
'name' => 'shipping-method',
'type' => 'Zend\Form\Element\Radio',
'options' => array(
'label' => 'Shipping Method',
'label_attributes' => array(
'class' => 'lbl-shipping-method'
),
'value_options' => array(
'Ground' => 'Ground',
'Expedited' => 'Expedited'
),
'disable_inarray_validator' => TRUE,
)
));
and remove setValueOptions and setDisableInArrayValidator from your view.
Hope this works.

Create a SelectBox using Form Helper in CakePHP3

I am trying to make a combo box for an edit page.
echo $this->Form->select('status',
['empty' => 'Select Status'],
['class' => 'form-control', 'required']
);
Here I want to add 2 things :
$options = array('0' => 'Inactive',
'1' => 'Active',
);
and selected value. suppose that is $status;
I tried with different options but sometime it do not add classes and sometime it shows options in tag
It will be great if somebody give clue.
Thanks
<?= $this->Form->input('status', [
'type' => 'select',
'options' => ['0' => __('Inactive') , '1' => __('Active')],
'empty' => __('Select Status'),
'class' => 'form-control',
'required' => true, 'label' => __('Type')
])
?>

Symfony, Hidden Form Field

i have problem with hiding my form fields. For example:
->add('new_password', 'repeated', array(
'first_options' => array(
'label' => 'Nowe hasło',
'attr' => array('style'=>'display:none;')),
'second_options' => array(
'label' => 'Powtórz nowe hasło',
'attr' => array('style'=>'display:none;')),
'mapped' => false,
'required' => false,
));
Field is not visible but label is visible. I want to have hidden field but label should be hidden to. I want to show it in Jquery after clicking on the button. Any ideas guys ?
First, this is not a Hidden Field Type but a repeated type you want to hide by passing a style='display:none;' attribute.
In general, if you don't want to display a given label, you may need to customize your form rendering.
For example,
{{ form_row(yourForm.new_password) }} {# in case you're using the form_row helper #}
should be replaced by
{{form_widget(yourForm.new_password) }}
Because form_row(yourForm.yourField) is in fact a shortcut for,
{{ form_errors(yourForm.yourField) }}
{{ form_label(yourForm.yourField) }}
{{ form_widget(yourForm.yourField) }}
Also,
Why do you need to hide a repeated password field this way?
If you want to show it only when you click on a button why dont you wrap the newPassword widget in a div with display none?
But if you want to add attributes to the label you can use the option label_attr like this:
{{ form_row(form.name, {'label_attr ':{'class':'hidden'}}) }}
or
->add('new_password', 'repeated', array(
'first_options' => array(
'label' => 'Nowe hasło',
'label_attr' => array('style'=>'display:none;')),
'second_options' => array(
'label' => 'Powtórz nowe hasło',
'label_attr' => array('style'=>'display:none;')),
'mapped' => false,
'required' => false,
));

How to validate a checkbox in ZF2

I've read numerous workarounds for Zend Framework's lack of default checkbox validation.
I have recently started using ZF2 and the documentation is a bit lacking out there.
Can someone please demonstrate how I can validate a checkbox to ensure it was ticked, using the Zend Form and Validation mechanism? I'm using the array configuration for my Forms (using the default set-up found in the example app on the ZF website).
Try this
Form element :
$this->add(array(
'type' => 'Zend\Form\Element\Checkbox',
'name' => 'agreeterms',
'options' => array(
'label' => 'I agree to all terms and conditions',
'use_hidden_element' => true,
'checked_value' => 1,
'unchecked_value' => 'no'
),
));
In filters, add digit validation
use Zend\Validator\Digits; // at top
$inputFilter->add($factory->createInput(array(
'name' => 'agreeterms',
'validators' => array(
array(
'name' => 'Digits',
'break_chain_on_failure' => true,
'options' => array(
'messages' => array(
Digits::NOT_DIGITS => 'You must agree to the terms of use.',
),
),
),
),
)));
You could also just drop the hidden form field (which I find a bit weird from a purist HTML point of view) from the options instead of setting its value to 'no' like this:
$this->add(array(
'type' => 'Zend\Form\Element\Checkbox',
'name' => 'agreeterms',
'options' => array(
'label' => 'I agree to all terms and conditions',
'use_hidden_element' => false
),
));
I had the same problem and did something similar to Optimus Crew's suggestion but used the Identical Validator.
If you don't set the checked_value option of the checkbox and leave it as the default it should pass in a '1' when the data is POSTed. You can set it if you require, but make sure you're checking for the same value in the token option of the validator.
$this->filter->add(array(
'name' => 'agreeterms',
'validators' => array(
array(
'name' => 'Identical',
'options' => array(
'token' => '1',
'messages' => array(
Identical::NOT_SAME => 'You must agree to the terms of use.',
),
),
),
),
));
This won't work if you use the option 'use_hidden_element' => false for the checkbox for the form. If you do this, you'll end up displaying the default NotEmpty message Value is required and can't be empty
This isn't directly related to the question, but here's some zf2 checkbox tips if you're looking to store a user's response in the database...
DO use '1' and '0' strings, don't bother trying to get anything else to work. Plus, you can use those values directly as SQL values for a bit/boolean column.
DO use hidden elements. If you don't, no value will get posted with the form and no one wants that.
DO NOT try to filter the value to a boolean. For some reason, when the boolean value comes out to be false, the form doesn't validate despite having 'required' => false;
Example element creation in form:
$this->add([
'name' => 'cellPhoneHasWhatsApp',
'type' => 'Checkbox',
'options' => [
'label' => 'Cell phone has WhatsApp?',
'checked_value' => '1',
'unchecked_value' => '0',
'use_hidden_element' => true,
],
]);
Example input filter spec:
[
'cellPhoneHasWhatsApp' => [
'required' => false,
],
]
And here's an example if you want to hide some other form fields using bootstrap:
$this->add([
'name' => 'automaticTitle',
'type' => 'Checkbox',
'options' => [
'label' => 'Automatically generate title',
'checked_value' => '1',
'unchecked_value' => '0',
'use_hidden_element' => true,
],
'attributes' => [
'data-toggle' => 'collapse',
'data-target' => '#titleGroup',
'aria-expanded' => 'false',
'aria-controls' => 'titleGroup'
],
]);
I'm a ZF2 fan, but at the end of the day, you just have to find out what works with it and what doesn't (especially with Forms). Hope this helps somebody!
Very old question, but figured it might still be used/referenced by people, like me, still using Zend Framework 2. (Using ZF 2.5.3 in my case)
Jeff's answer above helped me out getting the right config here for what I'm using. In my use case I require the Checkbox, though leaving it empty will count as a 'false' value, which is allowed. His answer helped me allow the false values, especially his:
DO NOT try to filter the value to a boolean. For some reason, when the boolean value comes out to be false
The use case is to enable/disable certain entities, such as Countries or Languages so they won't show up in a getEnabled[...]() Repository function.
Form element
$this->add([
'name' => 'enabled',
'required' => true,
'type' => Checkbox::class,
'options' => [
'label' => _('Enabled'),
'label_attributes' => [
'class' => '',
],
'use_hidden_element' => true,
'checked_value' => 1,
'unchecked_value' => 0,
],
'attributes' => [
'id' => '',
'class' => '',
],
]);
Input filter
$this->add([
'name' => 'enabled',
'required' => true,
'validators' => [
[
'name' => InArray::class,
'options' => [
'haystack' => [true, false],
],
],
],
])