Symfony 2 Forms Entity Field Type Grouping

Symfony 2 Forms entity Field Type grouping

This can be solved by using the group_by option:

$builder->add('services','entity', array(
'class' => 'MyBundle:Service',
'group_by' => 'serviceType',
'multiple' => true,
'expanded' => true
));

Option groups in symfony2 entity form type

I did a similar thing when handling with categories.

First, when you build the form, pass the list of choices as a result from a function getAccountList() as follows:

 public function buildForm(FormBuilderInterface $builder, array $options){
$builder
->add('account', 'entity', array(
'class' => 'MyBundle\Entity\Account',
'choices' => $this->getAccountList(),
'required' => true,
'empty_value' => 'Choose_an_account',
));
}

The function should do something like follows (the content depend on the way you structure your result).

private function getAccountList(){
$repo = $this->em->getRepository('MyBundle\Entity\Account');

$list = array();

//Now you have to construct the <optgroup> labels. Suppose to have 3 groups
$list['group1'] = array();
$list['group2'] = array();
$list['group3'] = array();

$accountsFrom1 = $repo->findFromGroup('group1'); // retrieve your accounts in group1.
foreach($accountsFrom1 as $account){
$list[$name][$account->getName()] = $account;
}
//....etc

return $list;
}

Of course, you can do it more dynamics! Mine is just a brief example!

You also have to pass the EntityManager to your custom form class. So, define the constructor:

class MyAccountType extends AbstractType {

private $em;

public function __construct(\Doctrine\ORM\EntityManager $em){
$this->em = $em;
}
}

And pass the EntityManager when you initiate the MyAccountType object.

Symfony2 Dynamic Groups of EntityType fields in form

The solution was actually simple after seeing this answer Symfony 2 Forms entity Field Type grouping

I just customized the rendering of the form. The best part is, I get all the helpful parts of Symfony forms (the data binding), but I can completely customize the rendering.

public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('courses', 'entity', array(
'class' => 'MyMainBundle:Course',
'property' => 'name',
'multiple' => true,
'expanded' => true
))
->add('save', 'submit')
;
}

There's a cool trick in the twig template to just rendering it myself. I did have to pass in the groups of courses.

The trick is to use {% do form.courses.setRendered %}

{{ form_start(form) }}
{{ form_errors(form) }}

{% for group in academics.courseGroups %}
<section>
<h2>
{{ group.name }}
</h2>
<p>{{ group.description }}</p>

{% for course in group.courses %}
<div class="form-group">
<div class="course">
<div class="checkbox">
<label for="my_mainbundle_application_course_courses_{{ course.id }}">
<input type="checkbox"
id="my_mainbundle_application_course_courses_{{ course.id }}"
name="my_mainbundle_application_course[courses][]"
value="{{ course.id }}"
{% if course.id in form.courses.vars.value and form.courses.vars.value[course.id] %}checked="checked"{% endif %}>
<span class="name">{{ course.name }}</span>
<span class="subject">({{ course.subject }})</span>
-
<span class="credits">{{ course.credits }} hours</span>
</label>
</div>
</div>
</div>
{% endfor %}
</section>
{% endfor %}

{% do form.courses.setRendered %}
{{ form_row(form.save) }}

{{ form_end(form) }}

Symfony2 grouped form items

Ok... So I found out, that group_by is used to get optgroup's in <select>. My EntityType has:

$builder->add('item', 'entity' array(
'class' => 'MyBundle:Item',
'property' => 'name',
'multiple' => true,
'expanded' => true,
'group_by' => 'group.name',
);

In my template:

{% form_theme form 'MyBundle::form_theme.html.twig' %}
{{ form_widget(form.item) }}
{{ form_rest(form) }}

In my form theme I just tried to replicate choice_widget_collapsed, but there are some differences (eg.: checking if value is checked). I don't know if it's the best way to do so, but it works for me. Maybe because I'm using just item entity selection and no other input fields.
My form theme:

{% block choice_widget_expanded %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% set options = choices %}
{{ block('choice_widget_expanded_options') }}
</div>
{% endspaceless %}
{% endblock choice_widget_expanded %}

{% block choice_widget_expanded_options %}
{% spaceless %}
{% for group_label, choice in options %}
{% if choice is iterable %}
<fieldset>
<legend>{{ group_label|trans({}, translation_domain) }}</legend>
{% set options = choice %}
{{ block('choice_widget_expanded_options') }}
</fieldset>
{% else %}
<input type="checkbox" name="{{ full_name }}[]" value="{{ choice.value }}"{% if value[choice.value] %} checked="checked"{% endif %}/> {{ choice.label|trans({}, translation_domain) }}
{% endif %}
{% endfor %}
{% endspaceless %}
{% endblock choice_widget_expanded_options %}

Any improvements are welcome.

Additional properties to entity Field Type in a form in Symfony2

Ok, in case somebody gets here with the same question, this is what I've done in the end:

I've created a custom field type (see http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html)

Since we is going to be an entity field in the end, you want to add:

    public function getParent() {
return 'entity';
}

When using it on the Form:

    $builder->add('creditcard', new CreditCardFieldType(),
array( 'label' => 'Credit Card',
'required' => true,
'expanded' => false,
'class' => 'Acme\Bundle\Entity\CreditCardCharge',
'property' => 'object',
'multiple' => false,
'query_builder' => function(\Acme\Bundle\Repository\CreditCardChargeRepository $er) {
return $er->createQueryBuilder('b');
},
'mapped' => false,
));

object is a new property added to the entity that contains the whole object, so I added to the entity:

public function getObject()
{
return $this;
}

This way we can access to the object from the template, we just need to create a new template for our own custom field type:

{% block creditcard_widget %}
{% spaceless %}
{% if required and empty_value is none and not empty_value_in_choices %}
{% set required = false %}
{% endif %}
<select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
{% if empty_value is not none %}
<option value=""{% if required and value is empty %} selected="selected"{% endif %}>{{ empty_value|trans({}, translation_domain) }}</option>
{% endif %}
{% if preferred_choices|length > 0 %}
{% set options = preferred_choices %}
{{ block('choice_creditcard_widget_options') }}
{% if choices|length > 0 and separator is not none %}
<option disabled="disabled">{{ separator }}</option>
{% endif %}
{% endif %}
{% set options = choices %}
{{ block('choice_creditcard_widget_options') }}
</select>
{% endspaceless %}
{% endblock creditcard_widget %}

{% block choice_creditcard_widget_options %}
{% spaceless %}
{% for group_label, choice in options %}
{% if choice is iterable %}
<optgroup label="{{ group_label|trans({}, translation_domain) }}">
{% set options = choice %}
{{ block('choice_creditcard_widget_options') }}
</optgroup>
{% else %}
<option value="{{ choice.data.creditcard }}" charge="{{ choice.data.charge }}" {% if choice is selectedchoice(data.creditcard_charges_id) %} selected="selected"{% endif %}>{{ choice.data.text|trans({}, translation_domain) }}</option>
{% endif %}
{% endfor %}
{% endspaceless %}
{% endblock choice_creditcard_widget_options %}

And register it for twig in your config.yml:

twig:
form:
resources:
- 'AcmeBundle:Form:creditcardfield.html.twig'

Not sure it is the best solution but it does the trick. Hope it helps.

How can I sort group_by option for entityType field in formbuilder?

You could sort the options by the group name via a custom QueryBuilder:

$builder->add('...', EntityType::class, [
'class' => YourEntity::class,
'query_builder' => function (EntityRepository $repository) {
return $repository->createQueryBuilder('entity')
->leftJoin('entity.category', 'category')
->addSelect('CASE WHEN entity.category IS NULL THEN \'all\' ELSE category.name END AS HIDDEN category_name')
->orderBy('category_name', 'ASC')
->addOrderBy('entity.name', 'ASC');
},
'group_by' => ...,
]);

https://symfony.com/doc/current/reference/forms/types/entity.html#ref-form-entity-query-builder

Symfony2 : Using group_by option in an entity field

I had a similar problem today.

I imagine you've been seeing a lot of PHP errors related to the incorrect use of Objects as Array keys? This is caused by Symfony trying to use the whole related object as the array key in the grouped results array.

I'll need to look further into it for a better solution but for the meantime this is what I'm using...

Add a new method to the Part entity called getClientName that looks like this:

public function getClientName()
{
// safety measure in-case a part hasn't been assigned to a project
if (null === $this->getProject()) {
return null;
}
// safety measure in-case a project hasn't been assigned to a client
if (null === $this->getProject()->getClient()) {
return null;
}
return $this->getProject()->getClient()->getName();
}

Set the group_by option to clientName in the form field builder:

$this->createFormBuilder()
->add('part','entity',array(
'class' => 'SGLFLTSPartBundle:Part',
// this property will be processed by Symfony as `$part->getClientName()`
'property' => 'clientName',
->getForm();

The idea behind the use of this extra method is to give Symfony a class method that it can call to get a string value to perform the grouping with.

If anyone else has a more elegant solution I'd be keen to see it.



Related Topics



Leave a reply



Submit