Forms With Checkboxes For Each Entity in Symfony: Difference between revisions
Jump to navigation
Jump to search
m (moved Multiple Checkboxes Without an Entity Class in Symfony to Forms With Checkboxes For Each Entity in Symfony: The original title represented an invalid concept.) |
No edit summary |
||
| Line 2: | Line 2: | ||
== Goal == | == Goal == | ||
To display a list of records, select the records with checkboxes, then apply a batch update to the records when the form is submitted.<ref>[http://stackoverflow.com/questions/14638794/build-a-form-having-a-checkbox-for-each-entity-in-a-doctrine-collection#answer-14653394 Build a Form Having a Checkbox For Each Entity in a Doctrine Collection], Stackoverflow<br />Take note of the following answer that points out how to correctly access the collection in the form data with the current version of Symfony.</ref> | |||
== Form class == | |||
<syntaxhighlight lang="php" highlight="9,15-19,27,33"> | |||
// src/AppBundle/Form/Type/PendingTutorialOptionType.php | |||
// ... | |||
use Symfony\Component\Form\AbstractType; | |||
use Symfony\Component\Form\FormBuilderInterface; | |||
use Symfony\Component\OptionsResolver\OptionsResolverInterface; | |||
class PendingTutorialOptionType extends AbstractType | |||
{ | |||
public function buildForm(FormBuilderInterface $builder, array $options) | |||
{ | |||
$builder->add('tutorialId', 'entity', array( | |||
'required' => false, | |||
'class' => 'AppBundle:TutorialTemp', | |||
'property' => 'id', | |||
'property_path' => '[id]', | |||
'multiple' => true, | |||
'expanded' => true | |||
)); | |||
$builder->add('update', 'submit', array('label' => 'save selected')); | |||
} | |||
public function setDefaultOptions(OptionsResolverInterface $resolver) | |||
{ | |||
$resolver->setDefaults(array( | |||
'data_class' => null | |||
)); | |||
} | |||
public function getName() | |||
{ | |||
return 'pending_tutorials'; | |||
} | |||
} | |||
</syntaxhighlight> | |||
* In the `buildForm()` routine, | |||
** Use `entity` as the field type. | |||
** Assign the entity type with the `class` option. | |||
** The `property` and `property_path` options assign the id field of the entity to the checkbox elements. | |||
** `multiple` and `expanded` options set to `true` cause the form to render with a series of checkboxes as opposed to text fields (or dropdowns if the field type was `choice`). | |||
* Important to set `data_class` to `null` in `setDefaultOptions()`. | |||
* Value returned by `getName()` is used to identify the form in the Twig template and to collect the form data after it is submitted. | |||
== Controller == | == Controller == | ||
| Line 113: | Line 161: | ||
* [http://tutorials.dbarchowsky.com/app_dev.php/pending Pending Tutorials], Tutorial Database | * [http://tutorials.dbarchowsky.com/app_dev.php/pending Pending Tutorials], Tutorial Database | ||
== Notes == | |||
<references /> | |||
Revision as of 14:23, 8 February 2015
Goal
To display a list of records, select the records with checkboxes, then apply a batch update to the records when the form is submitted.[1]
Form class
// src/AppBundle/Form/Type/PendingTutorialOptionType.php
// ...
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class PendingTutorialOptionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('tutorialId', 'entity', array(
'required' => false,
'class' => 'AppBundle:TutorialTemp',
'property' => 'id',
'property_path' => '[id]',
'multiple' => true,
'expanded' => true
));
$builder->add('update', 'submit', array('label' => 'save selected'));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => null
));
}
public function getName()
{
return 'pending_tutorials';
}
}
- In the
buildForm()routine,- Use
entityas the field type. - Assign the entity type with the
classoption. - The
propertyandproperty_pathoptions assign the id field of the entity to the checkbox elements. multipleandexpandedoptions set totruecause the form to render with a series of checkboxes as opposed to text fields (or dropdowns if the field type waschoice).
- Use
- Important to set
data_classtonullinsetDefaultOptions(). - Value returned by
getName()is used to identify the form in the Twig template and to collect the form data after it is submitted.
Controller
// ...
use Symfony\Component\HttpFoundation\Request;
//...
/**
* @Route("/pending", name="_pending")
*/
public function pendingAction(Request $request)
{
// retrieve pending tutorials from database
$groups = $this->getDoctrine()
->getRepository('AppBundle:TutorialGroupTemp')
->findAll();
$tutorial_data = array();
foreach($groups as $group) {
$group->getTutorials();
foreach ($group->tutorials as $tutorial) {
$tutorial_data[$tutorial->getId()] = $tutorial->getName();
}
}
// define form inputs
$fb = $this->createFormBuilder();
foreach($tutorial_data as $key => $label) {
$fb->add('tutorialId', 'choice', array(
'label' => 'Tutorials',
'multiple' => true,
'expanded' => true,
'choices' => $tutorial_data,
'required' => false
));
}
$fb->add('update', 'submit', array('label' => 'save selected'));
$form = $fb->getForm();
// process form submission
$form->handleRequest($request);
if ($form->isValid()) {
// collect form data
$data = $form->getData();
/** @todo process form data */
}
// display listings view
return $this->render("tutorials/pending.html.twig", array(
'groups' => $groups,
'form' => $form->createView()
));
}
// ...
- Store all the record values in an array to be assigned to the checkbox inputs elements.
- Use a form builder object to define the form.
- Call the
add()method for each checkbox to be added the form.- Checkboxes representing an array of choices are created using
choiceas the form element - The options 'multiple=true' and 'expanded=true' are what make it render as checkboxes as opposed to dropdowns.
- The values of the checkboxes are passed to the form builder with the
choicesoption.
- Checkboxes representing an array of choices are created using
- In this case submit buttons are repeated throughout the form for the convenience of not having to scroll through all the listings to find them.
- The
form_widget()twig routine will only render an input once because generally they are all assignedidattributes. - The submit button must still be added to the form builder in order to validate the form data.
- The
- Call the
- The form data is collected and processed with the
handleRequest()andgetData()calls. (getData()wouldn't be used if the form data was being assigned to an entity class.) - The form is validated with the
isValid()call. If form data is not being submitted, this block is quietly skipped over. - It's necessary to pass the form view to the template when rendering the view.
N.B. There are probably other things that I could do (form class? services?) that would be better practices. As documented here it works. Update with any new practices.
Template
{{ form_start(form) }}
{{ form_errors(form) }}
<button type="submit" class="btn btn-default" name="form[update]">save selected</button>
{% for tutorial in tutorials %}
{{ form_widget(form.tutorialId[loop.index0] ) }}
{% endfor %}
<button type="submit" class="btn btn-default" name="form[update]">save selected</button>
{% do form.update.setRendered %}{# compensates for manually inserting this multiple times in the form #}
{{ form_end(form) }}
- The checkboxes are rendered with
form_widget().tutorialIdcorresponds to the index of the checkbox collection added to the form builder object.- The individual checkboxes in the collection are accessed through a numeric index. Twig provides the
loop.index0helper.
- The html for the submit buttons are is manually inserted into the template. The Symfony helper functions will only render a form element once to avoid duplicate
idvalues. form_end()will render any fields that have not explicitly rendered in the form already.form.update.setRenderedprevents this.
Processing the form data
After the call to $form->getData(), the submitted form data will be accessible through an array:
array (size=1)
'tutorialID' =>
array (size=3)
0 => int 3
1 => int 6
2 => int 9
Examples
- Pending Tutorials, Tutorial Database
Notes
- ↑ Build a Form Having a Checkbox For Each Entity in a Doctrine Collection, Stackoverflow
Take note of the following answer that points out how to correctly access the collection in the form data with the current version of Symfony.