Toggle html validation globally

2019-09-14 06:10发布

问题:

I've made a couple of twig extensions but I'm stumped on this one.

I have the following template logic that I want to make into an extension.

I need reuse this logic into many different forms instead of copying and pasting the following code everywhere:

{% if html5validation is not defined %}
    {{ form_start(some_form) }}
{% else %}
    {% if html5validation %}
        {{ form_start(some_form) }}
    {% else %}
        {{ form_start
            (
                company, {'attr': {'novalidate': 'novalidate'}}
            ) 
        }}
    {% endif %}
{% endif %}

With the above code from the controller I can do the following to turn the html5 validator on and off:

$this->render(..., array(html5validation => false));

I want put the template logic into the twig extension below...

I just don't know if it's possible to implement what I've done above in a twig extension.

class HTML5Validation extends \Twig_Extension
{
    public function getFunctions()
    {
        return array(
            new \Twig_SimpleFunction('html5validation', array($this, 'setValidation')),
        );
    }

    public function setValidation($boolean)
    {
        //Implement the same logic as the twig template.
    }

    public function getName()
    {
        return 'html5validator';
    }
}

回答1:

The short answer is no - you can't do this using a twig extension, it's not what they're meant for.

Looking at your template fragment I'd say you need to customise the form_start block. To do this see Symfony Form Theming and How to customise form rendering.

EDIT: This solution does not work if your customised code requires local twig variables - only global twig variables are available for form theming. You can define your own twig globals in config.yml or in a twig extension.

For example, to override form_start globally, you find the default definition of the form_start block in form_div_layout.html.twig, copy it into your own form theme file e.g. YourBundle/Form/fields.html.twig, modify it as required and and update the twig configuration to apply your form theme file. Something like this:

{# src/YourBundle/Form/fields.html.twig #}
{% extends 'form_div_layout.html.twig' %}

{% block form_start -%}
    {% if html5validation is not defined %}
        {{ parent() }}
    {% else %}
        {% if html5validation %}
            {{ parent() }}
        {% else %}
            {{ parent
                (
                    company, {'attr': {'novalidate': 'novalidate'}}
                ) 
            }}
        {% endif %}
    {% endif %}
{%- endblock form_start %}

Config:

# app/config/config.yml
twig:
    form:
        resources:
            - 'YourBundle:Form:fields.html.twig'


回答2:

I actually found a better way to do what I wanted.

As a plus it works globally instead of having to populate more fields into your controller!

In YourBundle/Resources/views/validation.toggle.html.twig

{% extends 'form_div_layout.html.twig' %}

{% block form_start -%}
    {% if html5validation is defined and html5validation == false %}
        {% set attr = attr|merge({'novalidate': 'novalidate'}) %}
    {% endif %}
    {{ parent() }}
{%- endblock form_start %}

Then if you want to turn off html5 validation across the whole website:

# app/config/config.yml
twig:
    global:
        html5validation: false

Or

Even better just use it in your dev_config.yml if you want validation on by default on production mode but the ability to toggle validation on and off for dev mode.

# app/config/dev_config.yml
twig:
    global:
        html5validation: false
    resources:
        - 'YourBundle::validation.toggle.html.twig'

Finally use it in your twig template normally:

{% form_theme your_form 'YourBundle::validation.toggle.html.twig' %}

form_start(your_form)

Reusable and non invasive, exactly like I wanted it. :)

I got the hint from:

https://github.com/symfony/symfony/issues/11409#issuecomment-49358377



回答3:

In the absence of a more elegant solution, you can always put the twig fragment given in your question into a separate file and use twig include from your various forms. The included fragment has access to the variables from the surrounding context:

{# YourBundle/Resources/views/form_start.html.twig #}
{% if html5validation is not defined %}
    {{ form_start(some_form) }}
{% else %}
    {% if html5validation %}
        {{ form_start(some_form) }}
    {% else %}
        {{ form_start
            (
                company, {'attr': {'novalidate': 'novalidate'}}
            ) 
        }}
    {% endif %}
{% endif %}

Then in the twig file for the form:

{% include 'YourBundle::form_start.html.twig' %}

If you typically pass a 'form' variable into render() in your controller(s) then you can use that in your form_start fragment. Otherwise you can pass the appropriate form in as a variable:

{% include 'YourBundle::form_start.html.twig' with {'form': localForm} %}


标签: symfony twig