Symfony2 disable HTML5 form validation - php

I want to validate my form using server side validation only. However, if the browser supports HTML5 it validates using the HTML5 attributes added to the form by symfony2 so I need to prevent HTML5 validation.

Just add novalidate to your <form> tag:
<form novalidate>
If you are rendering the form in TWIG, you can use following.
{{ form(form, {'attr': {'novalidate': 'novalidate'}}) }}

I know its old question but with SF2.6 in FormType, you can do:
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'attr'=>array('novalidate'=>'novalidate')
));
}

While googling for a solution to this I found one, that seems the most elegant if you want to disable html5 validation in your whole app, so I thought i'd share it here. Credits go to the author of this blog article.
The idea is to create an extension for the "form" form type like this:
<?php
// src/AppBundle/Form/Extension/NoValidateExtension.php
namespace AppBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
class NoValidateExtension extends AbstractTypeExtension
{
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['attr'] = array_merge($view->vars['attr'], [
'novalidate' => 'novalidate',
]);
}
public function getExtendedType()
{
return 'form';
}
}
?>
Then you just register it in your services.yml like this:
app.no_validation_form_extension:
class: AppBundle\Form\Extension\NoValidateExtension
tags:
- {name: form.type_extension, alias: form}
and you're done. All your forms automatically have a novalidate attribute now.
Symfony 3.3
As of Symfony 3.3 the configuration is slightly different, but still possible.
Slight update to the getExtendedType method to return the FormType class.
// src/AppBundle/Form/Extension/NoValidateExtension.php
namespace AppBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\Type\FormType;
class NoValidateExtension extends AbstractTypeExtension
{
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['attr'] = array_merge($view->vars['attr'], [
'novalidate' => 'novalidate',
]);
}
public function getExtendedType()
{
return FormType::class;
}
}
Plus some a minor addition of the extended_type tag, which is now required in your service declaration:
app.no_validation_form_extension:
class: AppBundle\Form\Extension\NoValidateExtension
tags:
- {name: form.type_extension, alias: form, extended_type: Symfony\Component\Form\Extension\Core\Type\FormType}

Alternatively if for some reason you don't want to do it in twig as in the answer above...
{{ form(form, {'attr': {'novalidate': 'novalidate'}}) }}
or you create your from manually with createFormBuilder then you could simply use createFormBuilder as a second parameter to define form attribute:
//someAction
$form = $this->createFormBuilder(null, ['attr'=>['novalidate'=>'novalidate']])
->add(...)
->add(...)
->add(...)
->getFrom();
return $this->render("-----:----:----.html.twig", [
'form'=>$form->createView()
]);

If you are using Symfony 3 (or 2) and want to turn off validation for a specific field only you can do this.
$form = $this->createFormBuilder($task)
->add('task', TextType::class, array('required' => false))
->add('dueDate', DateType::class)
->add('save', SubmitType::class, array('label' => 'Create Task'))
->add('saveAndAdd', SubmitType::class, array('label' => 'Save and Add'))
->getForm();
In this sample form notice the array('required' => false), you can add this to any element that you want to disable validation for without disabling validation for the others. Very useful if you want to temporarily disable only one element instead of the entire form.
Note this ONLY disables the HTML5 validation! This does not disable server side validation.
Reference: http://symfony.com/doc/current/book/forms.html#field-type-options

If you actually need to remove the validation attributes (if you are using a validation library want to keep all of your validation constraints in one place for example), you can overwrite the widget_attributes block in twig.
If you are already using custom form templates in app/Resources/views/form.html.twig for example (and have enabled it in your config.yml) you can just add a block for
{% block widget_attributes %}
{% spaceless %}
id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}
{% for attrname, attrvalue in attr %}{% if attrname in ['placeholder', 'title'] %}{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}" {% else %}{{ attrname }}="{{ attrvalue }}" {% endif %}{% endfor %}
{% endspaceless %}
{% endblock widget_attributes %}
All I have done here is remove the attributes related to validation:
{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}

To disable Regex validation for specific field using formType class:
->add('foo',null,array=>('attr'=>('pattern'=>'/[^~,]/'))

Use form theming:
First create form theme template, e.g app/Resources/views/form/fields.html.twig:
{% extends 'form_div_layout.html.twig' %}{# or some other base layout #}
{% block form_start %}
{% if attr.novalidate is not defined %}
{% set attr = attr|merge({'novalidate':'novalidate'}) %}
{% endif %}
{{ parent() }}
{% endblock %}
Then use that form theme in your template:
{% form_theme form with 'form/fields.html.twig' %}
{{ form_start(form) }} <-- now renders with novalidate attribute
...
{{ form_end(form) }}
Or, apply theme globally (app/config/config.yml):
twig:
form_themes:
- ':form/fields.html.twig'

Related

Overriding the label of a single form field to include HTML in Symfony 4.4

I am having issues overriding a label in my form in my Symfony 4.4 application:
{{ form_row(form.legal, {
'label' : 'personal.form.fields.legal'|trans
}) }}
personal.form.fields.legal looks like this:
I agree that I am 18 and above, I have read and accept the T&Cs
My form definition:
->add('legal', CheckboxType::class,
'required' => true,
'mapped' => false,
])
My attempt at overriding this label is this:
{% block _crmbundle_personal_legal_label %}
<label{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %} style="color: red;">
{{ form_widget(form) }}
{{ label|unescape|raw }}
</label>
{%- endblock %}
I have a Twig extension that does this:
public function getFilters(): array
{
return [
new TwigFilter('unescape', function ($value) {
return html_entity_decode($value);
}),
];
}
I am finding this duplicates the label and I can't find a way to correct this. I have one checkbox, but two labels (both showing in red)

Override Bootstrap form template in Symfony2

Symfony 2.8
I'm trying to override some blocks of bootstrap themes for forms.
Particularly interested the block "form_label_class" in the theme "bootstrap_3_horizontal_layout.html.twig":
{% block form_label_class -%}
col-sm-2
{%- endblock form_label_class %}
I created the file my_form.html.twig and inherited it from "bootstrap_3_horizontal_layout.html.twig":
{% use "bootstrap_3_horizontal_layout.html.twig" %}
{% block form_start -%}
...
{% endblock form_start -%}
{% block form_label_class -%}
{{ width_test }}
{%- endblock form_label_class %}
Also added the definition of "width_test" in the form class:
....
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['width_test'] = $options['width_test'];
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('width_test', 3);
}
The problem: as a result of getting the error:
Variable "width_test" does not exist in form/my_form.html.twig
Importantly, "width_test" is not defined only in the block "form_label_class", but no problems to display it for example in the block "form_start"

Adding help block using form theming

In my app I'm trying to display form help block using tips from official Symfony2 cookbook. Here is my code:
{% extends 'form_div_layout.html.twig' %}
{% block form_widget_simple %}
{{ block('base_form_widget_simple') }}
{{ dump(help) }}
{% if help is defined %}
<span class="help">{{ help }}</span>
{% endif %}
{% endblock %}
And using this theme:
{{ form_row(form.pageTitle, {'help': 'some help'}) }}
With this I'm getting error Variable "help" does not exist. Any ideas what have I missed?
P.S. I use Symfony 2.7.1.
Create a Form type extension extending the form type:
namespace Acme\AppBundle\Form\Extension;
use ...
class FieldTypeHelpExtension extends AbstractTypeExtension
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->setAttribute('help', $options['help']);
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['help'] = $options['help'];
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'help' => null
]);
}
public function getExtendedType()
{
return 'form';
}
}
Define the extension as a service:
acme_app.form.extension.field_type_help:
class: Acme\AppBundle\Form\Extension\FieldTypeHelpExtension
tags:
- { name: form.type_extension, alias: form }
Create a template extending form div layout:
{% extends 'form_div_layout.html.twig' %}
{% block field_help %}
{% if help is defined and help %}
<p class="help-block">{{ help|trans }}</p>
{% endif %}
{% endblock field_help %}
{% block integer_widget %}
{{ parent() }}
{{ block('field_help') }}
{% endblock integer_widget %}
{% block form_widget %}
{{ parent() }}
{{ block('field_help') }}
{% endblock form_widget %}
Configure this template as form theme on config.yml
twig:
form_themes:
- 'Form/fields.html.twig'
Now you can use it when render the a field on a template:
{{ form_widget(form.name, { 'help': 'this is help' }) }}
Or in your Form type:
$form->add('name', 'text', ['help' => 'this is help']);

Can not submit form on click submit

Hello I want to create form and inserting record to mysql table on clicking on submit button in Symfony.
I am new in symfony. I have created form but it didn't response on submit. Here is my code
DefaultController.php
<?php
namespace Sym\FormBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sym\FormBundle\Entity\TblCust;
use Symfony\Component\HttpFoundation\Request;
use Sym\FormBundle\Form\TblCustType;
class DefaultController extends Controller
{
public function indexAction(Request $request)
{
$tbl = new TblCust();
// $form = $this->createForm(new TblCustType(),$tbl);
$form = $this->createFormBuilder($tbl)
->add('custName','text')
->add('custCity','text')
->add('custAddress','text')
->add('custPhno','text')
->add('save','submit')
->getForm();
$form->handleRequest($request);
if($form->isValid()){
$em = $this->getDoctrine()->getManager();
$em = persist('$tbl');
$em->flush();
return new response('New Customer Added..!');
}
$build['form']=$form->createView();
return $this->render('FormBundle:Default:index.html.twig',array( 'form' => $form->createView(),));
}
}
routing.yml
form_homepage:
pattern: /Form
defaults: { _controller: FormBundle:Default:index }
index.html.twig
{% block gender_widget %}
{% spaceless %}
{% if form %}
<ul {{ block('widget_container_attributes') }}>
{% for child in form %}
<li>
{{ form_widget(child) }}
{{ form_label(child) }}
</li>
{% endfor %}
</ul>
{% else %}
{# just let the choice widget render the select tag #}
{{ block('choice_widget') }}
{% endif %}
{% endspaceless %}
{% endblock %}
{% block container %}
{% endblock%}
I have created form using doctrine:generate:bundle symfony commend
TblCustType.php
<?php
namespace Sym\FormBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TblCustType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('custName')
->add('custCity')
->add('custAddress')
->add('custPhno')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Sym\FormBundle\Entity\TblCust'
));
}
/**
* #return string
*/
public function getName()
{
return 'sym_formbundle_tblcust';
}
}
My output is looking like below image
My problem is when i click on submit button it doesn't return response and i can not save my record. Please help my out this.
I believe you need to put the form tag in twig:
{{ form_start(form) }}
//all form widgets
//submit button
{{ form_rest(edit_form) }} <-- so it renders the hidden ones like the csrf token
</form>
You need to use form_start, form_rest and form_end like that :
{% block gender_widget %}
{% spaceless %}
{% if form %}
{{ form_start(form) }}
<ul {{ block('widget_container_attributes') }}>
{% for child in form %}
<li>
{{ form_widget(child) }}
{{ form_label(child) }}
</li>
{% endfor %}
</ul>
{{ form_rest(form) }}
{{ form_end(form) }}
{% else %}
{# just let the choice widget render the select tag #}
{{ block('choice_widget') }}
{% endif %}
{% endspaceless %}
{% endblock %}

HTML in Symfony2 form labels instead of plain text

I am trying to implement something like this:
<div>
<input type="checkbox" name="checkbox" id="checkbox_id" />
<label for="checkbox_id">I agree to the Terms of Service</label>
</div>
The closest I've come to implement this is through:
<div>
{{ form_widget(form.agreeWithTos) }}
<label for="{{ form.agreeWithTos.vars.id }}">I agree to the Terms of Service</label>
</div>
Is there a better way? Having to specify {{ form.agreeWithTos.vars.id }} is inelegant. :)
Solved this problem using the following code in my form-theme:
{# ---- form-theme.html.twig #}
{% block checkbox_row %}
{% spaceless %}
<div>
{{ form_errors(form) }}
<label class="checkbox" for="{{ form.vars.id }}">
{{ form_widget(form) }}
{{ label|default(form_label(form)) | raw }}
</label>
</div>
{% endspaceless %}
{% endblock %}
in your Form-Template you can then use:
{% form_theme form '::form-theme.html.twig' %}
{{form_row(form.termsOfServiceAccepted, {
'label' : 'I have read and agree to the Terms and conditions'
})
}}
this way, the block from the form-theme would apply to any checkbox on the page. If you need to also use the default-theme, you can add a parameter to enable special-rendering:
{# ---- form-theme.html.twig #}
{% block checkbox_row %}
{% spaceless %}
{% if not useTosStyle %}
{{ parent() }}
{% else %}
{# ... special rendering ... #}
{% endif %}
{% endspaceless %}
{% endblock %}
which would be used like this:
{% form_theme form '::form-theme.html.twig' %}
{{form_row(form.termsOfServiceAccepted, {
'useTosStyle' : true,
'label' : 'I have read and agree to the Terms and conditions'
})
}}
Thanks to a recent commit to Symfony, you can use label_html from Symfony 5.1 onward:
{{ form_label(
form.privacy,
'I accept the privacy terms.',
{
'label_html': true,
},
) }}
I've been beating my head over this then had a eureka moment. The easiest way to do this–BY FAR–is to create a Twig extension.
Here's my Twig code:
{# twig example #}
{% block form_label %}
{% set label = parent() %}
{{ label|unescape|raw }}
{% endblock %}
and PHP:
<?php
new Twig_SimpleFilter('unescape', function($value) {
return html_entity_decode($value);
});
A couple notes:
This unescapes all previously escaped code. You should definitely re-escape afterwards as necessary.
This requires an extends tag for your target form theme in your own custom form theme which you can use in your subsequent forms. Put the twig code in a custom form theme and replace references to your other form theme/themes with this one.
Overall this is the fewest lines of code for the biggest and best outcome that I've been able to find. It's also ultra-portable and DRY: You can extend any form theme and the label will change without you changing the rest of your code.
Another very simple approach is to override the form theme directly in the template which renders the form. Using {% form_theme form _self %} it is as simple as this:
{% form_theme form _self %}
{% block form_label %}
{{ label | raw }}
{% endblock %}
{{ form_start(form) }}
See the corresponding section in the docs:
https://symfony.com/doc/current/form/form_customization.html#method-1-inside-the-same-template-as-the-form
The easiest way to customize the [...] block is to customize it directly in the template that's actually rendering the form.
By using the special {% form_theme form _self %} tag, Twig looks inside the same template for any overridden form blocks. [...]
The disadvantage of this method is that the customized form block can't be reused when rendering other forms in other templates. In other words, this method is most useful when making form customizations that are specific to a single form in your application. If you want to reuse a form customization across several (or all) forms in your application, read on to the next section.
Another approach is to use a simple Twig replacement:
{% set formHtml %}
{{ form(oForm) }}
{% endset %}
{{ formHtml|replace({'[link]': '', '[/link]': ''})|raw }}
In your form, you have something like this in order to make it work:
$formBuilder->add('conditions', CheckboxType::class, [
'label' => 'Yes, I agree with the [link]terms and conditions[/link].'
]
);
Of course, you may change [link] to anything else. Please note that you do not use HTML tags ;-)
I think you are looking for form theming. That way you are able to style each part of form, in an independent file, anyway you want and then just render it in "elegant" way, row by row with {{ form_row(form) }} or simply with {{ form_widget(form) }}. It's really up to you how you set it up.
Symfony 4.2
TWIG:
{% block main %}
....
{% form_theme form _self %}
...
{{ form_row(form.policy, {'label': 'security.newPassword.policy'|trans({"%policyLink%":policyLink, "%termsLink%":termsLink})}) }}
...
{% endblock %}
{% block checkbox_radio_label %}
<label{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}>
{{- widget|raw }} {{ label|unescape|raw }}
</label>
{% endblock checkbox_radio_label %}
PHP:
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class AppExtension extends AbstractExtension
{
public function getFilters()
{
return [
new TwigFilter('unescape', function ($value) {
return html_entity_decode($value);
}),
];
}
}
So form theming is pretty complicated. The easiest thing I've found is to just suppress the field's label ('label'=> false in Symfony form class) and then just add the html label in the twig html.
You could leverage form theming in another way: you could move the <label> tag outside the form_label() function.
Create a custom form theme, and for checkboxes only move the <label> tag outside the form_label function:
{% block checkbox_row %}
<label>{{ form_label(form) }}</label>
{{ form_errors(form) }}
{{ form_widget(form) }}
{% endblock checkbox_row %}
{% block checkbox_label %}
{{ label }}
{% endblock checkbox_label %}
Now, in your teplate, override the label of your checkbox, and thus effectively inject HTML into the label function:
{% form_theme form 'yourtheme.html.twig' _self %}
{% block _your_TOS_checkbox_label %}
I agree with terms and conditions
{% endblock _your_TOS_checkbox_label %}

Categories