Process GET in Symfony-Form is always empty - forms

I try to implement a searchform in my Symfony-Application. POST works fine, but I want to use /search?q=foo. I have a form with method=GET but I can't bind my Request to the Form with the following Request:
search?form%5B_token%5D=HC5M4nG-B-r5BUUSmCchkryqNQyu9RvDDlTvcTDuFFY&form%5Bq%5D=foobar
This is my Form
$data = array();
return $this->createFormBuilder($data)
->add('q', 'text')
->getForm();
And the current Controller
/**
* #var $form Form
*/
$form = $this->getSearchForm();
if ($request->isMethod('GET')) {
// contains q = 'foobar'
dump($_GET);
// null
dump($request->request->get('q'));
// null
dump($request->request->get('form'));
$form->submit($request->request->get($form->getName()));
$form->handleRequest($request);
$data = $form->getData();
// null
dump($data);
...
}
the form-template
{{ form_start(form, {'action': path('search'), 'method': 'GET', 'attr': { 'class' : 'navbar-form navbar-left', 'role' : 'search' }}) }}
{{ form_errors(form) }}
<div class="form-group">
{{ form_label(form.q) }}
{{ form_errors(form.q) }}
{{ form_widget(form.q, { 'attr': {'placeholder': 'Find' }}) }}
</div>
<button type="submit" class="btn btn-default">Find</button>
{{ form_end(form) }}

$request->request->all() is all of the $_POST parameters.
$request->query->all() is all of the $_GET parameters.
You should be using $request->query->get('q') or $request->get('a') (which will go through each of the parameter bags) to get your parameters.
For more info see the docs.

Related

Symfony form CollectionType render the label only once

I have a SquadType form which contains an embedded SquadMemberType form as a collectionType field.
Each time I press the add squad member button on my form, I can add a squadMember form from the prototype. Works perfectly.
The fact is, each time I add a squadMember form, it displays the name and tag label. I want to find a way to display these labels only for the first squadMember but not for the others.
I tried to set label to false in the form squadMemberType class and to display it directly in the template with no success (didn't find a way to make it work).
Is there a way to achieve that ?
My main form :
class squadType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('squadName', TextType::class)
->add('squadDescription', TextareaType::class)
->add('squadMembers', CollectionType::class, [
'label' => ' ',
'entry_type' => SquadMemberType::class,
'entry_options' => [
'attr' => [
'class' => 'email-box',
'style' => 'display:flex; gap:1rem;',
]
],
'allow_add' => true,
])
->add(
'save',
SubmitType::class, ['label' => 'Create Squad']
)
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Squad::class,
]);
}
}
My embedded form :
class SquadMemberType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('squadMemberName', TextType::class, [
'label_attr' => [
'class' => 'formLabel',
],
'label' => 'Name',
])
->add('squadMemberTag', IntegerType::class, [
'label' => 'Tag',
// 'label' => false,
'label_attr' => [
'class' => 'formLabel',
],
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => SquadMember::class,
]);
}
}
My twig :
<div class="content">
{{ form_start(form, {'attr': {'class': 'form-horizontal', 'id': 'create-squad'}}) }}
<div class="creation-form">
<fieldset class="creation-form-globalInfo">
<div class="form-group {{ form.squadName.vars.valid==false ? "has-error" }}">
{{ form_label(form.squadName, null, {
'label': 'Squad Name',
'label_attr': {'class': 'control-label'}}) }}
<div class="">
{{ form_widget(form.squadName) }}
{{ form_errors(form.squadName) }}
</div>
</div>
<div class="form-group {{ form.squadDescription.vars.valid==false ? "has-error" }}">
{{ form_label(form.squadDescription, null, {
'label': 'Squad Description',
'label_attr': {'class': 'control-label'}}) }}
<div class="">
{{ form_widget(form.squadDescription) }}
{{ form_errors(form.squadDescription) }}
</div>
</div>
</fieldset>
<fieldset class="creation-form-info">
<ul id="squadMember-fields-list"
data-prototype="{{ form_widget(form.squadMembers.vars.prototype)|e }}"
data-widget-tags="{{ '<li></li>'|e }}"
data-widget-counter="{{ form.squadMembers|length }}"
class="squad-form">
{% for squadMemberField in form.squadMembers %}
<li>
{{ form_errors(squadMemberField) }}
{{ form_widget(squadMemberField) }}
</li>
{% endfor %}
</ul>
<button type="button"
class="add-another-collection-widget secundary-button"
data-list-selector="squadMember-fields-list">
{{ 'squad.add.squadMember.button.label'|trans }}
</button>
</fieldset>
</div>
<div class="validation-bottom">
{{ form_row(form.save,{
'label': 'squad.add.confirm.button',
'attr': {
'class': 'primary-button'
}
})
}}
</div>
{{ form_end(form) }}
</div>
my script :
{% block javascripts %}
<script>
$(document).ready( function () {
$('.add-another-collection-widget').click(function (e) {
var list = jQuery(jQuery(this).attr('data-list-selector'));
// Try to find the counter of the list or use the length of the list
var counter = list.data('widget-counter') || list.children().length;
// grab the prototype template
var newWidget = list.attr('data-prototype');
// replace the "__name__" used in the id and name of the prototype
// with a number that's unique to your emails
// end name attribute looks like name="contact[emails][2]"
newWidget = newWidget.replace(/__name__/g, counter);
// Increase the counter
counter++;
// And store it, the length cannot be used if deleting widgets is allowed
list.data('widget-counter', counter);
// create a new list element and add it to the list
var newElem = jQuery(list.attr('data-widget-tags')).html(newWidget);
newElem.appendTo(list);
});
</script>
{% endblock %}

Pass a foreach loop of forms to Twig

I am creating an edit page where there will be as many forms as there will be results from my query. So after my query, I created a foreach loop to pass each "result" to a form and then I pass it all to my Twig.
$repo = $this->getDoctrine()->getRepository(Classement::class);
$q = $repo->createQueryBuilder('c');
$q->select('c', 'h')
->join('c.clubHistos', 'h')
->where('c.country = '.$country)
->where('c.season = '.$season);
$result = $q->getQuery()->getResult();
foreach ($result as $table) {
$table = $table;
$form = $this->createForm(ClassementType::class, $table);
}
return $this->render('back/editDivisionTables.html.twig', array(
'form' => $form->createView(),
'table' => $table
));
The problem is that I am only getting the last form when I should be having all of them. I did a dump($form) in my loop and everything seemed okay. So the problem is either in my return statement or in my Twig.
{{ form_start(form) }}
<div class="season-table-info">
<div class="country">
{{ form_row(form.country) }}
</div>
<div class="division">
{{ form_row(form.division) }}
</div>
{{ form_row(form.season) }}
</div>
<table id="dynamic-club-table">
<thead></thead>
<tbody id="dynamic-club-table-body" data-row-prototype="{{ formMacro.form(form.clubHistos.vars.prototype)|e('html_attr') }}">
{% for clubHistos in form.clubHistos %}
{{ formMacro.form(clubHistos) }}
{% endfor %}
</tbody>
</table>
{{ form_end(form) }}
I tried this solution but it didn't do the trick.

Why does Symfony 3.4 form displays EntityType choices with label although 'label' => false was used?

I am working on an existing Symfony 3.4 based project and trying to add and render a new form. Although the 'label' => false option was used, the fields are rendered including a label. Why?
// Symfony
class SomeController extends Controller {
public function userListAction(Request $request) {
$users = $someService->getUsers();
$formBuilder = $this->createFormBuilder()
->add('users', EntityType::class, [
'label' => false, // also tested '' and 'someLabel'
'class' => 'AppBundle:User',
'choices' => $users,
'multiple' => true,
'expanded' => true,
]);
$variables = array(
'form' => $formBuilder->getForm()->createView(),
);
return $this->render('AppBundle:Pages:user_list.html.twig', $variables);
}
}
// Twig
{% extends 'AppBundle::layout.html.twig' %}
{% block page_content %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% endblock %}
This shows a list of checkboxes for all users including the username as label.
Where does Symfony get the information to use the username as label? As far as I know no custom form widget was defined for the User class. Is there any way to check this for sure? Maybe there is something hidden in the vendor bundles like FOSUserBundle?
Why is the 'label' => false option ignored?
Edit:
Different ways of rendering the form does not solve the problem:
{{ form_start(form) }}
{{ form_row(form) }}
{{ form_end(form) }}
Result:
<div id="form_users">
<div class="form-group">
<div class="checkbox">
<label for="form_users_547">
<input type="checkbox" id="form_users_547" name="form[users][]" value="547">
someUserName
</label>
</div>
</div>
</div>
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
Result:
<div id="form_users">
<div class="checkbox">
<label for="form_users_547">
<input type="checkbox" id="form_users_547" name="form[users][]" value="547">
someUserName
</label>
</div>
</div>
{{ form_start(form) }}
{% for userFormView in form.users %}
{{ form_row(userFormView) }}
{% endfor %}
{{ form_end(form) }}
Result:
Basically the same as before with form_row
You need to use ‘choice_label’ => ‘YOUR PROPERTY PATH’ in the field options.
Pretty match is written in the docs: https://symfony.com/doc/current/reference/forms/types/entity.html#choice-label
If the entity class cast to string then is used if is not it will throw an exception. It looks like your entity User cast to the user name and that’s why it works.
You should try to use {{ form_row(form) }} which should render the whole field correctly.

Submit Button is not rendered in Symfony 2.x Form

I'm creating a from using Symfony Form builder, and rendering it using twig.
Here is my form builder code:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text', array(
'required' => TRUE,
))
->add('link', 'text', array(
'required' => TRUE,
))
->add('submit', 'submit', array(
'attr' => array(
'class' => 'btn btn-primary btn-sm custom-btn'
)
))
;
}
And my twig template is like this:
{{ form_start(form)}}
<div>
{{ form_label(form.name) }}
{{ form_widget(form.name) }}
</div>
<div>
{{ form_label(form.link) }}
{{ form_widget(form.link) }}
</div>
<div>
{{ form_widget(form.submit) }}
</div>
{{ form_end(form) }}
In this case, I'm getting everything as expected, except the submit button. Instead of custom submit button created in form builder, it is rendering default submit button with a label create.
What I'm doing wrong here?
Seems it is some issue with 'submit' name. For example, next example works:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
.... // your fields here
->('my_button', 'submit');
}
Then in the twig template:
<div>
{{ form_widget(form.my_button) }}
</div>
UPDATED : according to http://symfony.com/doc/current/reference/forms/twig_reference.html you can use {{ form_widget(form.submit, {'label': 'submit'}) }}. So next lines renders submit with 'submit' name:
{{ form_start(form) }}
{{ form_widget(form.text) }}
{{ form_widget(form.code) }}
{{ form_widget(form.submit, {'label': 'submit'}) }}
{{ form_end(form) }}
And you don't need to add submit to your FormType in this case.

problems with request in a embed form

HEllo sorry but my english isnt good.
I'm developing an application in Symfony 2.3.6 where i have to save in a DB (postgres) the values from a user.
The problem happens when my embed form (pais + region) that has 2 submit buttons the user press the second button. The system throw
Child "salvar_region" does not exist.
The question is how can I detect if the second button is being pressed if the system is throwing an exception?
Here is my Default controller
public function addLocalAction(Request $request)
{
$region = new Region();
$localidad = new Pais();
$localidad->setRegion($region);
$form = $this->createForm(new localidadType(), $localidad);
if($request->isMethod('POST')){
$form->handleRequest($request);
$form->getData();
if ($form->get('salvarPais')-> isClicked()){
$objeto = new Pais();
$objeto->setNombrePais($form->get('nombrePais')->getData());
$em = $this->getDoctrine()->getManager();
$em->persist($objeto);
$em->flush();}
if ($form->get('salvarregion')->isClicked()){
$objeto = new Region();
$objeto->setNombreRegion($form->get('nombreRegion')->getData());
$objeto->setNombreRegion($form->get('numeroRegion')->getData());
$em = $this->getDoctrine()->getManager();
$em->persist($objeto);
$em->flush();}
return $this->redirect($this->generateUrl('localidades'));
}
return $this->render('plataformaPlataformaBundle:Default:localidades.html.twig', array('form'=> $form->createView()));
}
My html.twig
<form action="{{ path('localidades')}}" method="post" {{ form_enctype(form) }}>
<h3>Agregar País</h3>
<div class="pais">
{{ form_row(form.nombrePais) }}
{{ form_row(form.salvarPais) }}
</div>
<form action="{{ path('localidades')}}" method="post" {{ form_enctype(form) }}>
<h3>Agregar Region</h3>
<div class="region">
{{ form_start(form) }}
{{ form_errors(form)}}
{{ form_row(form.region.nombreRegion) }}
{{ form_row(form.region.numeroRegion) }}
{{ form_row(form.region.pais) }}
{{ form_row(form.region.salvarregion) }}
{{ form_end(form) }}
</div>
</form>
and my 2 type forms
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('nombreRegion', 'text', array('label' => 'Nombre de Región: '));
$builder->add('numeroRegion', 'integer', array('label' => 'Número de Región: '));
$builder->add('pais', 'entity', array('label' => 'País al que pertenece: ',
'class' => 'plataformaPlataformaBundle:Pais',
'property' => 'nombrePais'));
$builder->add('salvarregion', 'submit', array('label' => 'Guardar Región'));
$builder->getForm();
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('nombrePais', 'text');
$builder->add('salvarPais', 'submit', array('label' => 'Guardar País'));
$builder->add('region', new regionType());
$builder->getForm();
}
PD: A lot of thanks if someone can help me
PDx2: here is an example of the URL request:{"region":{"nombreRegion":"ewrew","numeroRegion":"4","pais":"3","salvarregion":""},"_token":"853d5460b076e01fdf4cef4c59c33e836ab64af3"}
The error you got doesn't look like the name you gave the button during the builder process.
Anyway, to tell if a specific submit was clicked you can use:
if($form->get('salvarregion')->isClicked()) {
}