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.) |
|||
| (3 intermediate revisions by the same user not shown) | |||
| 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 == | ||
<syntaxhighlight lang="php" highlight=" | <syntaxhighlight lang="php" highlight=""> | ||
// | // src\AppBundle\Controller\DefaultController.php | ||
//... | //... | ||
public function pendingAction(Request $request) | public function pendingAction(Request $request) | ||
{ | { | ||
// | // get all the available options | ||
$ | $pending_options = $this->get('app.pending_tutorial_options') | ||
->getTutorialOptionsList(); | |||
-> | |||
// get a form object, passing it the available options | |||
$form = $this->createForm(new PendingTutorialOptionType(), $pending_options); | |||
// process form submission | // process form submission | ||
$form->handleRequest($request); | $form->handleRequest($request); | ||
// check if form data was submitted | |||
if ($form->isValid()) { | if ($form->isValid()) { | ||
// collect form data | // collect selected entities from form data | ||
$data = $form->getData(); | $data = $form['tutorialId']->getData(); | ||
/ | $selected_ids = array(); | ||
foreach($data as $tutorial) { | |||
// $data is a collection of PendingTutorial objects with all their data | |||
array_push($selected_ids, $tutorial->getId(); | |||
} | |||
// do something with the matching records... | |||
// ... | // ... | ||
</syntaxhighlight> | </syntaxhighlight> | ||
`$form->getData()` returns a collection of all the available options in the form. `$form['tutorialId']->getData()` returns the selected options as entity objects. | |||
'''''N.B.''' I was having difficulty with `isValid()` because I was manually inserting the submit buttons in the form, with a name value of `form[update]`. The form class returns `pending_options` as its name; the correct value for the submit button's name should have been `pending_options[update]`.'' | |||
== Template == | == Template == | ||
| Line 99: | Line 112: | ||
== Processing the form data == | == Processing the form data == | ||
After the call to `$form->getData()`, the submitted form data will be accessible through | After the call to `$form['tutorialId']->getData()`, the submitted form data will be accessible through a Doctrine ArrayCollection of entity objects: | ||
<syntaxhighlight lang="text"> | <syntaxhighlight lang="text"> | ||
object(Doctrine\Common\Collections\ArrayCollection)[1583] | |||
private '_elements' => | |||
array (size=6) | |||
0 => | |||
object(AppBundle\Entity\PendingTutorial)[652] | |||
... | |||
1 => | |||
object(AppBundle\Entity\PendingTutorial)[660] | |||
... | |||
2 => | |||
object(AppBundle\Entity\PendingTutorial)[664] | |||
... | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 113: | Line 132: | ||
* [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 /> | |||
Latest revision as of 01:18, 10 February 2015
Goal[edit]
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[edit]
// 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[edit]
// src\AppBundle\Controller\DefaultController.php
//...
public function pendingAction(Request $request)
{
// get all the available options
$pending_options = $this->get('app.pending_tutorial_options')
->getTutorialOptionsList();
// get a form object, passing it the available options
$form = $this->createForm(new PendingTutorialOptionType(), $pending_options);
// process form submission
$form->handleRequest($request);
// check if form data was submitted
if ($form->isValid()) {
// collect selected entities from form data
$data = $form['tutorialId']->getData();
$selected_ids = array();
foreach($data as $tutorial) {
// $data is a collection of PendingTutorial objects with all their data
array_push($selected_ids, $tutorial->getId();
}
// do something with the matching records...
// ...
$form->getData() returns a collection of all the available options in the form. $form['tutorialId']->getData() returns the selected options as entity objects.
N.B. I was having difficulty with isValid() because I was manually inserting the submit buttons in the form, with a name value of form[update]. The form class returns pending_options as its name; the correct value for the submit button's name should have been pending_options[update].
Template[edit]
{{ 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[edit]
After the call to $form['tutorialId']->getData(), the submitted form data will be accessible through a Doctrine ArrayCollection of entity objects:
object(Doctrine\Common\Collections\ArrayCollection)[1583]
private '_elements' =>
array (size=6)
0 =>
object(AppBundle\Entity\PendingTutorial)[652]
...
1 =>
object(AppBundle\Entity\PendingTutorial)[660]
...
2 =>
object(AppBundle\Entity\PendingTutorial)[664]
...
Examples[edit]
- Pending Tutorials, Tutorial Database
Notes[edit]
- ↑ 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.