Symfony2, delimiters for a form - forms

I noticed that when I generate a form with a builder like this:
$builder
->add('valide')
->add('adresse', new \Acme\CoreBundle\Form\AdresseType())
->add('prestations', 'entity', array(
'class' => 'AcmeAppartBundle:Prestation',
'property' => 'nom',
'multiple' => true,
'expanded' => true)
);
The 'presations' field (which is a complete form) can be rendered with twig like that :{{ form(form.prestations) }}
My question is : is there a way to do the same for the rest of the form? I mean the same that : {{ form(form) }}
But without the {{ form(form.prestations) }} part included in. (how to define 'sections' of a form in the formType)?

If you need to change the render order so that form.presentations is rendered first and then the rest of the form, you can simply do this:
{{ form(form.prestations) }}
{{ form_rest(form) }}
When you do form_rest(form) it will render everything that hasn't been rendered before.
From the documentation:
This renders all fields that have not yet been rendered for the given
form. It's a good idea to always have this somewhere inside your form
as it'll render hidden fields for you and make any fields you forgot
to render more obvious (since it'll render the field for you).

If you have parts of the form that you want to add/remove depending on certain conditions, you should use form events.
Take a look at the documentation here - http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

Related

Symfony form theme custom attribute on row

Okay, so I have a form theme for custom radio button. In the form theme I render the label as an image. The image is basically a call to a route (which returns BinaryResponse):
<img src="{{ path('the_route_name', {'slideImage': value}) }}" class="slideImage">
Now, this works, however, the same form type needs to be used for slideshow background selector. The rendering is the same, however the route call and parameters are different.
Slide image: showSlideImage with parameter slideImage
Slideshow background: showBackgroundImage with parameter slideshowBackground
What my idea was, is to send a custom data attribute to the form for the route name (I can make both parameters the same name to avoid that issue).
I tried the following in my twig template where the form is rendered:
{{ form_row(form.background, {'attr': {'data-path': 'path'}}) }}
(background is an EntityType with multiple as false and expanded as true)
However, when I put a dump in my form theme
{{ dump(attr) }}
It shows an empty array. I've tried changing attr to row_attr but that didn't change anything. How can I send a custom data attribute to the form theme for it to render?
Seems like I had to use choice_attr:
'choice_attr' => function($choice, $key, $value) {
return ['path' => 'showSlideImage'];
},
I tried using choice_attr before, but I wasn't using a callback function and thus I did it the wrong way. And then I can just use attr.path to get the right value.

Symfony2 First form entity overriding second

I have a contact form on a page that has a name field, email field and textarea field. It is made in the most simple way...
$contactEntity = new ContactEntity();
$builder-> $this->container->get('form.factory')->createBuilder('form', $kontaktEntity, array();
$builder->add() ... fields added
Then, in the administrative area, I have a search form that searches for the reacivied messages with name and email fields. I create that form with a different entity with the fields name and email that are one of half a dozen other fields in ContactEntity.
The problem is that the search form is rendered in twig as if it was kontakt form.
To clarify, SearchEntity has fields name and email. ContactEntity also has the same fields but with addition of some other fields. When the search form is rendered in twig, it shows the name and email fields as if it were part of ContactEntity.
Also, twig customization doesn't work. I cannot change label text values, I cannot remove HTML5 validation, and can't do anything beacuse nothing works. I tried renaming the fields in the search entity but it doesn't work.
Twig rendering is made on diffrenet twig scripts and is normal and basic in both both forms. This is on a search form. Changing label taxt to Name doesn't work. The submit value, on the other hand, is correctly rendered.
{{ form_start(form, {attr: {'no-validate' : 'novalidate'}}) }}
<div class="search-rom">
{{ form_label(form.name, 'Name') }}
{{ form_errors(form.name) }}
{{ form_widget(form.name) }}
</div>
<div class="search-rom">
{{ form_label(form.email, 'Email') }}
{{ form_errors(form.email) }}
{{ form_widget(form.email) }}
</div>
{{ form_end(form) }}
To summarize, twig is rendering two of the fields of an entity that the built form has nothing to do with.
EDIT
I've just tested if SearchEntity is filled when form is submitted and it is, with the correct values. I really don't know what is going on here.
EDIT 2
This is a code fragment from the messageAction() method in the controller.
$searchEntity = new SearchEntity();
$builder = $this->container->get('form.factory')->createBuilder('form', $searchEntity, array());
$builder->add('name', 'text')
->add('email', 'text')
->getForm();
Then form is rendered in the response with $form->createView()
Maybe you don't need to pass the builder an entity. In other examples you can just create the entity after getting the data.
How to render a form without a class in other service?
http://symfony.com/doc/current/book/forms.html#using-a-form-without-a-class
I found what the problem is. It's translations.
I'm Croatian and site I'm building has two languages, english and croatian with english as the default locale. Translation is done in various ways, but the translation of forms and all that comes with forms is done via messages.en.php.
For translations, i choose array type. message.en.php looks like this...
... Some data to translate ...
'Ime' : 'Personal name or bussiness'
'Email' : 'Email address
... Some other data to translate
So, when twig tried to render this...
form_label(form.ime, 'Ime')
it rendered the translation for key Ime. Same thing happend to email field. Everything else is in order. I just changed the label value to 'Search for name' or something like that.
As to how to limit translations to only one form, I don't know. I read Translations section but couldn't find anything.

Mapping a deeply-nested property_path to a parent form

I'm building a form in Symfony 2 whose fields will vary depending on how the corresponding entity is configured.
Briefly, each entity has a set of "detail" fields that can hold different types and configurations of data.
For example, a Project entity might have the following configuration:
url renders as a text input and validates as a URL with max length of 300 chars.
description renders as a textarea with no validation constraints.
logo renders as a file input and validates as an image file with max dimensions of 500x500.
And so on. The part that makes this interesting is that all of this is configured via database tables so that an administrator could change the configuration of these models via a UI.
The (relevant part of the) database structure looks something like this:
project stores the Project records.
project_detail stores the value of each detail field for each Project.
detail_type defines the type and configuration for each detail field.
detail_type_assignment defines which detail types are available for each entity and the order in which the fields should display on forms.
Everything is working great so far except for rendering error messages in forms.
When any of these detail fields generates a validation error, it is displayed at the top of the form:
Note in the above image, "EIN" is a field that exists in the Project entity (i.e., implemented the normal way for a Symfony form), while "URL" and "Logo Upload" are implemented as detail fields.
Here's what the ProjectType looks like:
class ProjectType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('ein', 'ein')
;
/* Add detail fields to the form builder. */
foreach($this->getDetailTypes() as $detailType)
{
$slug = $detailType->getSlug();
$formatter = $detailType->createFormatterInstance('');
$builder->add(
$slug
, $formatter->getFormFieldType()
, $formatter->getFormFieldOptions()
);
/* E.g.,
*
* $builder->add(
* 'url'
* , 'text'
* , array('label' => 'URL', ...)
* )
*/
}
}
...
}
I'm pretty sure what's going on here is that the ViolationMapper can't translate the property_path correctly.
For example, at runtime, the property_path of the url value is project.details[url].value, but the field is located at project.url.
I would prefer not to construct a complex form hierarchy so that the position of each field matches its property_path. Is there a way I can change path that violations get added to in the ExecutionContext?
In your view I feel like you shouldn't use form(form) inside of form_start(form) and form_end(form). I believe that would generate the <form> tag twice
Old answer:
Idk what your twig looks like but I'm assuming somehow the error in the form row isn't being displayed. http://symfony.com/doc/current/book/forms.html#rendering-a-form-in-a-template talks about it.
From the link:
{# src/Acme/TaskBundle/Resources/views/Default/new.html.twig #}
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.task) }}
{{ form_row(form.dueDate) }}
{{ form_end(form) }}
Take a look at each part:
form_start(form) - Renders the start tag of the form.
form_errors(form) - Renders any errors global to the whole form (field-specific errors are displayed next to each field);
form_row(form.dueDate) - Renders the label, any errors, and the HTML form widget for the given field (e.g. dueDate) inside, by default, a div element;
form_end() - Renders the end tag of the form and any fields that have not yet been rendered. This is useful for rendering hidden fields and taking advantage of the automatic CSRF Protection.
form_row can be split into each of its parts:
<div>
{{ form_label(form.task) }}
{{ form_errors(form.task) }}
{{ form_widget(form.task) }}
</div>
and the form_errors() function should display what you want.

Displaying Zend Subform Errors in parent Zend Form

I am aware that form errors can be set to render at the top of the form using decorator code such as:
$form->setDecorators(array(
array('FormElements'),
array('FormErrors'),
However, I have subforms within my (parent) form and I need to render the subforms errors - aggregated and rendered at the top of the parent form. How can this be achieved please? Thanks.
I am a bit new to Zend but I have a similar implementation that acheives this. Although I also have extra code in here that makes the errors display in a custom manner and also puts the subforms into seperate divs.
The important parts to notice are the facts that the errors are turned off on both forms by not specifying the decorator FormErrors and then creating a new errors decorator on the parent form.
On my main form I've added a FormErrors decorator such as this:
$form->setDecorators(array(
new Zend_Form_Decorator_FormErrors(array(
'ignoreSubForms'=>false,
'markupElementLabelStart'=> '<p>',
'markupElementLabelEnd'=> '</p>',
'markupListStart'=>'<div class="formErrors">',
'markupListEnd' => '</div>',
'markupListItemStart'=>'<div>',
'markupListItemEnd'=>'</div>'
)),
'FormElements'
));
Then on the subform you turn off the form errors
$subForm->setDecorators(array(
'FormElements',
array(
array('data' => 'HtmlTag'),
array('tag' => 'div', 'class' => 'formRow')
)
));

Zend_Form - prefix text using decorator

I want to prefix the form title within the form tags, but above the form elements.
<form>
<h3>Login Form</h3>
<!-- form elements -->
</form>
I do not want to use a view script.
I thought of using the Description decorator, but that appears to be only available to the elements.
How do I set an arbitrary description for a form, and position it (either append / prepend) within the form tags? I have a feeling I need to play with the HtmlTag decorator but I've played with it and can't get the right results.
Typical. Ask a question, work out the solution.
$form->setDecorators(array(
array(
'Description',
array(
'tag' => 'div',
'class' =>'title'
)
),
'FormElements',
'Form'
))
->setDescription('Enter Login Credentials:');
Depending where you place the description decorator will determine where in the form tags it displays, i.e. place above 'FormElements' to display above the elements; place below 'FormElements' to display the description below the elements; place below the 'Form' decorator to display after the form tags.