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
Why Is My Downloaded File Is Always Damaged or Corrupted
How to Get Order Id in Woocommerce_Email_Headers Hook
How to Execute MySQL Script with Variables Using PHP::Pdo
.Htaccess Rewriterule: Two Domains Using Same Server and Directory
Linkify Regex Function PHP Daring Fireball Method
Regular Expression to Remove CSS Comments
In PHP, Which Is Faster: Preg_Split or Explode
Share Session Between Two Websites
Set Value of Single Object in Multidimensional Array in Twig Template
Insert a Persian Text in MySQL Table
How to Use Multiple PHP Header Content Types on the Same Page? Is This Possible
Get a Single Row from the Database Using Ajax in Codeigniter
Use of Undefined Constant Stdin - Assumed 'Stdin' in C:\Wamp\Www\Study\Sayhello.PHP on Line 5
Mod_Rewrite to Remove .PHP But Still Serve the .PHP File
Where to Use MySQL_Real_Escape_String to Prevent SQL Injection