Issue
I have a filter form in Symfony, which can filter for an Entity. For this purpose, I have a field with an EntityFilterType
(Lexik\Bundle\FormFilterBundle\Filter\Form\Type\EntityFilterType
), which simply extends Symfony's builtin EntityType
.
Now I want to add an "all" and a "none" option to this EntityType
. If it was a ChoiceType
, I would simply change the choices
array, but the EntityType
only accepts valid Entity-IDs as its value on submit and also only Entities in the array given to the 'choices' option.
My question is: How can I add additional options to an EntityType
form field? Besides the ugly way to reimplement the Entity-stuff into a ChoiceType
field? Any ideas on this? Am I missing a documented way?
Greets, spackmat
Solution
Some years have passed and the setting shines up again:
I have a ManyToMany related Entity that I want to filter for using the LexikFormFilterBundle. But I also want to allow to filter explicitly for Entities that have no such related Entity. In my case I want to allow to filter for ToDos that are assigned to some specific Users, but allow also to filter for ToDos that are not assigned at all. So the problems begin.
My solution for now is, indeed, switching to a ChoiceType::class
and that looks like this:
// We are in a buildForm function of a Filter-Form extending
// Symfony\Component\Form\AbstractType and using The LexikFormFilterBundle
// prepare the choices with a "none"-choice on top
// feel free to add also a "all"-choice, if that is needed
$myChoices = [
'None of those' => 'none',
];
foreach ($this->myWhateverRepository->getMyChoices() as $myChoice) {
// where $myChoice is some related Entity
$myChoices[$myChoice->getIdentifyingName()] = $myChoice->getId();
}
/*
now we have an array like this:
[
'None of those' => 'none',
'One related Entity' => 2,
'Another related Entity' => 4,
]
*/
$builder
->add('relatedWhatevers', ChoiceFilterType::class, [
'choices' => $myChoices,
'multiple' => true,
'label' => 'Filter for related whatevers',
'required' => false,
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
if (count($values['value']) === 0) {
// nothing to filter here
return null;
}
$orNone = in_array('none', $values['value']);
$myWhateverIds = array_filter($values['value'], function($v) { return 'none' !== $v; });
// join the related field and don't forget to do that as an
// innerJoin, otherwise the isNull() doesn't find anything
$query = $filterQuery->getQueryBuilder();
$query->leftJoin($field, 'myWhatever');
if ($orNone) {
if (count($userIds) > 0) {
$expression = $filterQuery->getExpr()->orX(
$filterQuery->getExpr()->isNull('myWhatever'),
$filterQuery->getExpr()->in('myWhatever.id', $myWhateverIds)
);
}
else {
$expression = $filterQuery->getExpr()->isNull('myWhatever');
}
}
else {
$expression = $filterQuery->getExpr()->in('myWhatever.id', $userIds);
}
return $filterQuery->createCondition($expression, []);
},
])
;
And that works: I can find ToDos assigned to some Users and/or are assigned to nobody. And when I don't fill the field, the filter does not do anything.
Answered By - spackmat Answer Checked By - Cary Denson (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.