Symfony: How to avoid custom form-types getting wrapped in a div automatically? - symfony

UserType Form:
class UserType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('email', 'email', ['label' => 'EMail']);
// various other fields....
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'validation_groups' => array('registration'),
'data_class' => 'Vendor\Model\Entity\User',
));
}
public function getName()
{
return 'form_user';
}
}
TutorType Form:
class TutorType extends Translate
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('user', new UserType(), ['label' => false]);
$builder->add('school', 'entity', [
'class' => 'Model:School',
'property' => 'name',
'label' => 'Label'
]);
// Various other fields
$builder->add('save', 'Submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
//'validation_groups' => array('registration'),
'data_class' => 'Vendor\Model\Entity\Tutor',
'cascade_validation' => true,
));
}
public function getName()
{
return 'form_tutor';
}
}
When rendering, the UserType is rendered inside a div, i cant find a way to overcome this.
The Form is rendered as
<form name="form_tutor"
method="post"
action=""
novalidate="novalidate"
class="form-horizontal form-horizontal"
id="form_tutor">
<div id="form_tutor"
novalidate="novalidate"
class="form-horizontal">
<div class="form-group">
<div class="col-lg-10">
<div id="form_tutor_user">
<div class="form-group">
<label class="col-lg-2 control-label aaaa required"
for="form_tutor_user_email">EMail</label>
<div class="col-lg-10">
<input type="email"
id="form_tutor_user_email"
name="form_tutor[user][email]"
required="required"
class="form-control" />
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label aaaa required"
for="form_tutor_tutorType">Type</label>
<div class="col-lg-10">
<select id="form_tutor_tutorType"
name="form_tutor[tutorType]"
class="form-control">
</select>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button type="submit"
id="form_tutor_save"
name="form_tutor[save]"
class="btn btn-default">Speichern</button>
</div>
</div><input type="hidden"
id="form_tutor__token"
name="form_tutor[_token]"
class="form-control"
value="s6i6zPxJs7KU5CiEe8i6Ahg_ca8rc2t5CnSk5yAsUhk" />
</div>
</form>
The form_tutor_user is wrapped in a own form-group div.
I tried to overwrite the form_tutor_user_widget but this is one level to deep. (And only a quick fix, it should be globally applied to all form type - Classes)
How can i change the theme so all custom types are not wrapped with the default form_row template?
Or how do i know in twig when a "subform" is rendered?
so i can decide to print the <div class="form-group"> when the child-node is not a subform, or skip it, if this is the case.
TIA

By default, in the base form theme:
{% block form_row %}
{% spaceless %}
<div>
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
And, for custom compound forms:
{% block form_widget_compound %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% if form.parent is empty %}
{{ form_errors(form) }}
{% endif %}
{{ block('form_rows') }}
{{ form_rest(form) }}
</div>
{% endspaceless %}
{% endblock form_widget_compound %}
Unless you changed something here, the DIV you see should come from either one or the other bit of template.
However, in your specfic example, if form_tutor_user_row is defined, the first bit is never used, and if form_tutor_user_widget is defined, the last bit is never used.
Back to your question. Your question is :
"How can i change the theme so all custom types are not wrapped with the default form_row template?"
Here is the problem the way I see it: you want that your TOP forms (the form in which all sub-forms are included) all have a common way of rendering, in sections. Each section will be included in a DIV with class="form-group". You may want to throw in some additional rendering operations but I will limit myself to this to keep things simple.
What you need to do then is to create a specfic form type and make all your TOP forms inherit from this new form type. For instance:
class TopType extends AbstractType
{
public function getName()
{
return 'top_form';
}
}
... and an inherited form:
class MyFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
...
}
public function getName()
{
return 'my_form';
}
public function getParent()
{
return 'top_form';
}
}
As you can see, there is no need to make PHP inheritance for form theming inheritance to work.
Template-theming-wise (can I even say that?), if no specific form theming is set for my_form, Symfony will understand that the default form theme to use here is the form theme of top_form, that you can define as such:
{% block top_form_widget %}
{% spaceless %}
{% for child in form %}
<div class="form-group">
{{ form_widget(child) }}
</div>
{% endfor %}
{{ form_rest(form) }}
{% endspaceless %}
{% endblock top_form_widget %}
I should add that this is a problem I already encountered and solved. Tell me how that works for you.
Edit:
To sum it up, what you have to do is:
Create the TopType form type,
Add the top_form_widget block in your form theme,
For all your root forms (i.e. top-level forms, forms that have no parent), add a getParent() method that will return the name of your TopType form ("top_form")

In theory, if you override the form_widget_compound block in a global form theme this way, it should work as you want:
// app/Resources/views/form.html.twig
{% block form_widget_compound %}
{% if form.parent is empty %}
<div {{ block('widget_container_attributes') }}>
{{ form_errors(form) }}
{% endif %}
{{ block('form_rows') }}
{{ form_rest(form) }}
{% if form.parent is empty %}
</div>
{% endif %}
{% endblock %}
And register your form theme:
// app/config/config.yml
twig:
form:
resources:
- "::form.html.twig"

I usually solve this problem by rendering the nested form's fields manually:
{{ form_row(form.tutor.school) }}
{{ form_row(form.tutor.user.email) }}
Probably that's not the most elegant solution, but it works for me and I haven't looked for an elegant one yet.

Bootstrap 3.3.4 I ended up doing this.
They key part of this:
<div class="{% if form.parent.parent is empty %}form-group{% endif %}{% if (not compound or force_error|default(false)) and not valid %} has-error{% endif %}">
Full template.
{% block form_row -%}
<div class="{% if form.parent.parent is empty %}form-group{% endif %}{% if (not compound or force_error|default(false)) and not valid %} has-error{% endif %}">
{% if form.parent.parent is null and label is not empty %}
{{- form_label(form) -}}
{% elseif label is empty %}
{{- form_label(form) -}}
{% endif %}
{% if compound is empty %}<div class="{{ block('form_group_class') }}">{% endif %}
{{- form_widget(form) -}}
{{- form_errors(form) -}}
{% if compound is empty %}</div>{% endif %}
</div>
{%- endblock form_row %}

Maybe it is not an elegant solution, however works for me, because I was also trying to find the solution.
As an example:
{% for custom_field in form.custom_fields %}
<div class="edit_custom">
{{ form_row(custom_field.name) }}
{{ form_row(custom_field.value) }}
</div>
{% endfor %}
<script>
$('.edit_custom').find('input').unwrap();
</script>

Try using form_themes.
First, in you parent template define the form theme:
{% form_theme form with ['BundleName:ControlerName:somesubform_form.html.twig'] %}
btw replace BundleName, ControllerName and somesubform with the proper names.
then render it with:
{{ form_row(form.somesubform) }}

Related

Symfony: trying to customize a collection form prototype

I have this form:
class BillType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('user')
->add('numberPlate')
->add('servicesPerformed', CollectionType::class, array(
'label' => false,
'entry_type' => ServicePerformedType::class,
'allow_add' => true,
))
->add('Save', SubmitType::class)
;
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'DefaultBundle\Entity\Bill'
));
}
being ServicePerformedType class this:
class ServicePerformedType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('description', TextareaType::class, array('label' => false))
->add('price', TextType::class, array('label' => false))
->add('quantity', TextType::class, array('label' => false));
}
}
And this template to render the form:
{{ form(form) }}
Add service
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script type="text/javascript">
var index = 0;
$('a').on('click', function() {
var prototype = $('#bill_servicesPerformed').data('prototype');
prototype = prototype.replace(/_name_/g, index.toString());
$('#bill_servicesPerformed').html(prototype);
index++;
})
</script>
As it is said in the docs, to get a custom prototype I should add the lines below at the top of my template:
{% form_theme form _self %}
{% block _servicesPerformed_entry_widget %}
I WILL WRITE MY CUSTOM PROTOTYPE HERE
{% endblock %}
But when I press Add service I dont get the text I WILL WRITE MY CUSTOME PROTOTYPE HERE, but the description, fields and quantity related to the ServicePerformedType class as before..
NOTE: maybe there are other ways to custom a form prototype, but I'm interested on this, so will be very thankful to someone who give a solution related to this way to custom form prototypes, thanks.
I must warn you that customizing the prototype could be a bit tricky. If you change your FormType fields you'll need to go through the template and make the same changes as well or your form will fail to render.
What I like to do is to create a custom template for that specific field and then customize it appropriately. So, looking at your code I would do something like this:
Create a page template - the one you'll use to render the entire page, including the form.
{# MyBundle/Resources/views/myPage.html.twig #}
{% extends "::base.html.twig" %}
{# This will tell the form_theme to apply the
`MyBundle:form/fields/servicePerformed.html.twig` template to your "form" #}
{% form_theme form with [
'MyBundle:form/fields/servicePerformed.html.twig'
] %}
{% block body %}
<div>
{{ form_start(form) }}
{{ form_rest(form) }}
{{ form_end(form) }}
</div>
{% endblock %}
Now you'll need to create the template MyBundle/Resources/views/form/fields/servicePerformed.html.twig. It will be used to customize only the servicePerformed field. The template should look something like this
{% macro service_template(fields) %}
<tr>
<td>I WILL WRITE MY CUSTOM PROTOTYPE HERE</td>
</tr>
{% endmacro %}
{#
The block name must match your field name!
You can find it by going into the debug toolbar -> Forms ->
click on your form field and then search for "unique_block_prefix".
Copy that and add "_widget" at the end.
#}
{% block _service_performed_widget %}
<table data-prototype="{{ _self.service_template(form.vars.prototype)|e }}">
{% for fields in form.children %}
{{ _self.service_template(fields) }}
{% endfor %}
</table>
{% endblock %}
I want to note that in the field template I'm passing the original prototype _self.service_template(form.vars.prototype). By doing this, you can use the original fields and render them in your customized prototype. For example this code:
{% macro service_template(fields) %}
<tr>
<td>{{ form_widget(fields.description) }}</td>
</tr>
{% endmacro %}
Will result in something like the following rendered prorotype:
<tr>
<td>
<input type="text" id="service_performed___name___description" name="service[__name__][description]"/>
</td>
</tr>
You can then manipulate it using your javascript.
I hope this helps you.
Actually form theme blocks that start with an underscore _ relate to a field with a specific name.
What I mean is that, if your master form BillType is called my_form, you will need to do this:
{% form_theme form _self %}
{% block _my_form_servicesPerformed_entry_widget %}
I WILL WRITE MY CUSTOM PROTOTYPE HERE
{% endblock %}
The problem with this approach is that it concerns a specific iteration of BillType. If you use this form type elsewhere and provide it with a different name my_form_2, you would have to add an identical block named _my_form_2_servicesPerformed_entry_widget.
You can use macro, have a look at below example it's working fine for me even in Symfony3. Using this example you will be able to format your collection prototype as well.
View
{% macro widget_prototype(widget, remove_text) %}
{% if widget.vars.prototype %}
{% set form = widget.vars.prototype %}
{% set name = widget.vars.name %}
{% else %}
{% set form = widget %}
{% set name = widget.vars.full_name %}
{% endif %}
<div data-content="{{ name }}" class="panel panel-default">
<div class="section row">
<div class="col-md-12">
<label class="field-label">Skill <span class="text-danger">*</span></label>
<label class="field select">
{{ form_widget(form.skill) }}
<i class="arrow double"></i>
</label>
</div>
</div>
<div data-content="{{ name }}">
<a class="btn-remove" data-related="{{ name }}">{{ remove_text }}</a>
{{ form_widget(form) }}
</div>
</div>
{% endmacro %}
Your template to render the form has some problems. The first is this line:
prototype = prototype.replace(/_name_/g, index.toString());
The regex should be __name__.
Next, you are retrieving the prototype, but then immediately overwriting it and replacing the HTML of the prototype. There is nothing there I can see that actually appends the new form to your existing form anywhere. Plus since you just have a string of text, that replace isn't going to find any text __name__ to replace.
You should post the full extent of your Twig/Javascript so we can actually see the #bill_servicesPerformed as well as everything else you are trying to do. Before you write a custom prototype you should get the form working with the standard prototype just to make sure you don't have any bugs there first.
As an example, this is the way I keep going it. I do not know if there are some reasons not to, so be careful.
Form to include prototype:
<div class="modal-body" id="contactMehtods" data-prototype="
{% filter escape %}
{{ include(':organization/partials:prototype_contact_method.html.twig', { 'contact_method': contact_form.contactMethods.vars.prototype }) }}
{% endfilter %}">
<div class="form-group">
{{ form_label(contact_form.name, null, { 'label_attr': { 'class': 'control-label' }}) }}
{{ form_widget(contact_form.name, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
Prototype template:
<div class="form-group">
{{ form_label(contact_method.name, null, { 'label_attr': { 'class': 'col-sm-3 control-label' }}) }}
<div class="col-sm-9">
{{ form_widget(contact_method.name, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
<div class="form-group">
{{ form_label(contact_method.value, null, { 'label_attr': { 'class': 'col-sm-3 control-label' }}) }}
<div class="col-sm-9">
{{ form_widget(contact_method.value, {'attr': {'class': 'form-control'}}) }}
</div>
</div>
But a note to consider, the javascript needs to accommodate for these changes I guess.

Symfony PUGX Bundle - Passing custom variables

I use PUGX Bundle for managing my users.
I want simply pass to the registration template, somes custom variables, but I don't know how to do !
Here the code of the controller :
/**
* #Route("/register", name="company_registration")
*/
public function registrationCompanyAction(Request $request)
{
return $this->container
->get('pugx_multi_user.registration_manager')
->register('AppBundle\Entity\Company');
}
Where can I do ?
Custom variables can be rendered in templates if they are defined in the form type shown in config.yml, e.g.,
config.yml
...
pugx_multi_user:
users:
staff:
entity:
class: Truckee\MatchingBundle\Entity\Staff
# factory:
registration:
form:
type: Truckee\UserBundle\Form\StaffFormType
name: staff_registration
validation_groups: [Registration, Default]
template: TruckeeUserBundle:Staff:staff.form.html.twig
Form type
class StaffFormType extends BaseType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('organization', new OrganizationType())
;
}
public function getName()
{
return 'staff_registration';
}
...
}
staff form template
{% block content %}
<h4 onclick="orghelp();" title="Click for help">{{label_info('Staff Registration Form <span class="glyphicon glyphicon-question-sign"></span>') }}</h4>
<div id="dialog"><style>.ui-dialog-titlebar-close {
display: none;
}</style></div>
{% block fos_user_content %}
{% include 'TruckeeUserBundle:Staff:staff_content.html.twig' %}
{% endblock fos_user_content %}
{% endblock %}
content template
{% trans_default_domain 'FOSUserBundle' %}
<form action="{{ path('staff_registration') }}" method="POST" class="form-inline">
{%if form._token is defined %}{{ form_widget(form._token) }}{% endif %}
{{ bootstrap_set_style('form-inline') }}
{% include "TruckeeUserBundle:Person:person_manage.html.twig" %}
<p><strong>Organization</strong></p>
<div id="orgNotice"></div>
{% set staff = form %}
{% set form = form.organization %}
<div id="orgForm">
{% include "TruckeeMatchingBundle:Organization:orgForm.html.twig" %}
<div>
{{ bootstrap_set_style('') }}
{% set form = staff %}
{{ form_widget(form.save) }}
</div>
</div>
</form>

How to detect widget type in Symfony Twig rendering?

For rendering form rows, I need to detect what type of widget is being rendered. For example for checkboxes I want the label before the input, so I did this:
{% block form_row %}
{% spaceless %}
<div class="row">
{% if form.vars.block_prefixes[1] == "checkbox" %}
{{ form_widget(form) }}
{{ form_label(form) }}
{{ form_errors(form) }}
{% else %}
<div class="small-12 medium-3 columns">
{{ form_label(form) }}
</div>
{{ form_widget(form) }}
{{ form_errors(form) }}
{% endif %}
</div>
{% endspaceless %}
{% endblock form_row %}
I used form.vars.block_prefixes[1] to determine the widget it's about to render. Is that right? Or is there a better method? I can't seem to find it in the docs.
If you see symfony cookbook, you can find:
the block name is a combination of the field type and which part of the field is being rendered (e.g. widget, label, errors, row)
So, to customize checkbox form type rendering, you can define checkbox_widget block and checkbox_row for widgets order:
{% block checkbox_widget %}
{% spaceless %}
<label {% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ label }}
</label>
<input type="checkbox" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
{% endspaceless %}
{% endblock checkbox_widget %}
{% block checkbox_row %}
{% spaceless %}
{{ form_widget(form) }}
{{ form_errors(form) }}
{% endspaceless %}
{% endblock checkbox_row %}
If there is any data you need in the templates and symfony doesn't provide it by default you can always create a form type extension
A form type extension is a mechanism that let's you extend many form types in a single place. You can extend all form types provided you define the right extended type (FormType::class if you want to extend all forms).
This extension provides both the block_type for the current instance and the class name for all form types. This let's you use these variables in any generic template (such as widget_attributes).
I only tested it on symfony 3.4
<?php
namespace YourBundle\Form\Extension;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\FormType;
class FormTypeExtension extends AbstractTypeExtension
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
$type = $form->getConfig()->getType();
$inner_type = $type->getInnerType();
$view->vars = array_replace($view->vars, array(
'block_prefix' => $type->getBlockPrefix(),
'type_name' => get_class($inner_type)
));
}
public function getExtendedType()
{
return FormType::class;
}
}

Symfony2 and form theming/customization (required/help/errors)

Maybe I'm overlooking something, and hopefully this is done very easy.
I have a form and what I want in the end is the following result:
Fields which:
are mandatory/required
have an error currently
have help
should get an extra a-Tag after the label and an extra div, filled with the help and/or the error, if applicable.
What I got to work is, that required fields get the a-Tag by using this:
{% use 'form_div_layout.html.twig' with field_label as base_field_label %}
{% block field_label %}
{{ block('base_field_label') }}
{% if required %}
<span> </span>
{% endif %}
{% endblock %}
So, what I tried already were different versions of this:
{% use 'form_div_layout.html.twig' with field_label as base_field_label %}
{% block field_label %}
{{ block('base_field_label') }}
{% if required or help is defined %}
<span> </span>
{% endif %}
{% endblock %}
{% block field_row %}
{% spaceless %}
<div class="row">
{% if required or help is defined %}
<div>
{{ form_errors(form) }}
{{ help }}
</div>
{% endif %}
{{ form_label(form) }}
{{ form_widget(form, { 'attr': {'class': 'grid_4'} }) }}
</div>
{% endspaceless %}
{% endblock field_row %}
And I can't get this to work.
So my questions are:
Where do I get the help text from, which can also contain HTML? I tried this within the form builder without success - but at least with an exception:
$builder ->add('subject', 'text', array(
'label' => 'Subject',
'help' => 'Can be formatted content with <strong>HTML-Elements</strong>',
));
How can I tell that the current field has an error (to add a class to the row) and if so also display it? {{ form_errors(form) }} did not output anything, no matter where I place it within `field_row˚.
There is no help text, you have to create Form Extension for field and add it to default options.
Example in SF 2.1 Beta 1:
namespace Webility\Bundle\WebilityBundle\Form\Extension;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormViewInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class HelpFormTypeExtension extends AbstractTypeExtension
{
public function buildView(FormViewInterface $view, FormInterface $form, array $options){
$view->setVar('help', $options['help']);
}
public function getExtendedType(){
return 'field';
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'help' => null
));
}
}
And register it as a service:
<service id="webility.form.extension.help" class="Webility\Bundle\WebilityBundle\Form\Extension\HelpFormTypeExtension">
<tag name="form.type_extension" alias="field" />
</service>
For the errors question:
Do you have any errors to print? Check that in controller if validation fails:
echo '<pre>'; print_r( $form->getErrorsAsString() ); echo '</pre>'; exit;
To solve it as stated in my question Maciej Pyszyński's anwser was very helpful.
I solved it in this case in another way, which I also want to post here. According to the manual "Adding "help" messages" I build this:
Note This solution won't work together with the formbuilder and needs some tweaking in twig.
To get the help ''-tags (actually they are divs now) …
{% block field_label %}
{{ block('base_field_label') }}
{% if attr.class is defined and '_hint' == attr.class %}
<div>
<a><span class="help">Help Icon</span></a>
<div class="tooltip">
{% if help is defined %}
{{ help|raw }}
{% else %}
Somebody forgot to insert the help message
{% endif %}
</div>
</div>
{% endif %}
{% endblock %}
To get the right class on an error
{% block field_row %}
{% spaceless %}
<div class="row{% if form_errors(form) %} error{% endif %}">
{{ form_label(form) }}
{{ form_widget(form, { 'attr': {'class': 'grid_4'} }) }}
</div>
{% endspaceless %}
{% endblock field_row %}
And the call from the template
<div class="row{% if form_errors(form.url) %} _error{% endif %}">
{{ form_label(form.field, null, { 'attr': {'class': '_hint'}, 'help': 'Help text or variable containing it' }) }}
{{ form_widget(form.field, { 'attr': {'class': 'grid_4'} }) }}
</div>

How to render form_rest() as hidden fields in Symfony2/Twig?

I have a Form class that contains many fields. I would like to render few of them and pass the left ones as hidden. How is this possible ?
I would like to do something like {{ form_rest(form, {'display': 'hidden'}) }} or <div display="hidden">{{ form_rest(form) }}</div>.
Example :
<form action="{{ path('fiche_intervention', {'rreid': rre.rreid}) }}" method="post" {{ form_enctype(form) }}>
{{ form_errors(form) }}
<div class="bloc-input">{{ form_label(form.rredatecommencement, "Date de retrait :") }}
{{ form_widget(form.rredatecommencement) }}
</div>
{# Some other fields... #}
{# ... #}
{# /Some other fields... #}
<div display="hidden">{{ form_rest(form) }}</div>
<input type="submit" />
</form>
You have to do it in you buildForm function, inside the "FormController". Just adding 'hidden' when you add the field is enough.
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name');
$builder->add('email', 'email');
$builder->add('subject');
$builder->add('anyone', 'hidden');
}
Also you may set all your unneeded fields as rendered in your twig template:
<form action="{{ path('fiche_intervention', {'rreid': rre.rreid}) }}" method="post" {{ form_enctype(form) }}>
{{ form_errors(form) }}
<div class="bloc-input">{{ form_label(form.rredatecommencement, "Date de retrait :") }}
{{ form_widget(form.rredatecommencement) }}
</div>
{% do form.unneededfield1.setRendered %}
{% do form.unneededfield2.setRendered %}
{% do form.unneededfield3.setRendered %}
<div display="hidden">{{ form_rest(form) }}</div>
<input type="submit" />
</form>
form_rest() renders all non-rendered fields from your form. It just renders them as they are, so if you want to render remaining fields as 'hidden', you just have to define them as 'hidden' in your Form !
{{ form_end(form, {'render_rest': false}) }}
It's from the official documentation (v3.0) so it's pretty much best practise i guess.

Resources