Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort a entity type field (without using query_builder option) in Symfony?

I need to custom sort entity type field, but without query_builder option. I need to sort it based on some information not available at database-level (hence, not using the query_builder).

Is there a way I can sort the elements of the <select> widget?

EDIT: I have a parent self-association in my section table, which contains also a title property:

+--------------+-----------+--------+
| section_id   | parent_id | title  |
+--------------+-----------+--------+
|            1 |      NULL | Parent |
+--------------+-----------+--------+
|            2 |          1| Child  |
+--------------+-----------+--------+
|            3 |          2| Nephew |
+--------------+-----------+--------+

I'd like to show a select box where items are sorted by a concatenation of its title and ancerstor's titles, i.e:

Parent
Parent/Child
Parent/Child/nephew

Not easy to accomplish with a single SQL select, so I need a way to get the options and simple sort by this "path".

like image 817
gremo Avatar asked Oct 03 '13 11:10

gremo


3 Answers

You can default sort a relationship in the entity by doing this:

/**
 * @ManyToMany(targetEntity="Group")
 * @OrderBy({"name" = "ASC"})
 **/
private $groups;

More info: Ordering To-Many Associations

like image 143
Baba Yaga Avatar answered Nov 10 '22 04:11

Baba Yaga


If I understand the OP correctly, the sorting is merely for displaying the select options in order for the user's benefit.

Add a function to your form type like this:

public function finishView(FormView $view, FormInterface $form, array $options)
{
    usort($view->children['select']->children, function(FormView $a, FormView $b) {
        return strcasecmp($a->vars['value']->getFullTitle(), $b->vars['value']->getFullTitle());
    });
}

This example assumes a getFullTitle() function exists on your entity which can generated the value to use for sorting comparisons. select would be the fieldName of the relationship the select box will be based on.

5 Years later...

Trying my own solution again in Symfony 4, this doesn't seem to work.

This is the solution that did work:

public function finishView(FormView $view, FormInterface $form, array $options)
{
    usort($view->children['select']->vars['choices'], function(ChoiceView $a, ChoiceView $b) {
        return strcasecmp($a->label, $b->label);
    });
}
like image 31
Henry Avatar answered Nov 10 '22 04:11

Henry


I would suggest to add a "path" field on your section. And as soon as you call $parent->addChild($child) I would set the $child->path to $parent->path . $child->path. This is the only way if you want to filter within sql.

You could also consider using the Tree extension that uses nested sets in order to improve performance on this kind of operations: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/tree.md

like image 1
m0c Avatar answered Nov 10 '22 02:11

m0c