#forms #symfony
#формы #symfony
Вопрос:
У меня есть форма фильтра в Symfony, которая может фильтровать сущность. Для этой цели у меня есть поле с EntityFilterType
функцией ( LexikBundleFormFilterBundleFilterFormTypeEntityFilterType
), которое просто расширяет встроенную функцию Symfony EntityType
.
Теперь я хочу добавить к этому опции «все» и «нет» EntityType
. Если бы это было a ChoiceType
, я бы просто изменил choices
массив, но EntityType
он принимает только действительные идентификаторы объектов в качестве своего значения при отправке, а также только объекты в массиве, заданные параметру «выбор».
Мой вопрос: как я могу добавить дополнительные параметры в EntityType
поле формы? Помимо уродливого способа переопределения сущности в ChoiceType
поле? Есть идеи по этому поводу? Мне не хватает документированного способа?
Приветствую, spackmat
Комментарии:
1. Вам нужно что-то еще, что
query_builder
позволяет фильтровать объекты?2.
query_builder
Определяет запросы, которые ограничивают выбор объектов, перечисленных в виджете. Кроме того, мне нужно еще несколько параметров / вариантов, которые не являются сущностями, а другими значениями, которые может использовать контроллер (или, в моем случае, логика фильтра).3. Ну, я думаю об
EntityType::class
обходном пути расширения формы, но я не уверен, что именно вам нужно.4. Это было бы лучшим способом, чем внедрение специфичного для объекта кода в ChoiceType::class . Спасибо, хорошая идея. Я надеялся, что есть более простой способ и люди, имеющие ту же проблему.
5. Это немного сложно, но вы можете использовать FormEvents или преобразователь данных для перехода к полю во время отправки или рендеринга поля. Соответствует ли это тому, на что вы надеетесь?
Ответ №1:
Прошло несколько лет, и настройка снова появляется:
У меня есть объект, связанный с ManyToMany, который я хочу отфильтровать для использования LexikFormFilterBundle. Но я также хочу разрешить явную фильтрацию для объектов, у которых нет такого связанного объекта. В моем случае я хочу разрешить фильтровать задачи, которые назначены некоторым конкретным пользователям, но также разрешить фильтровать задачи, которые вообще не назначены. Итак, начинаются проблемы.
Смотрите также эту проблему в LexikFormFilterBundle
Мое решение на данный момент, действительно, переключается на a ChoiceType::class
и выглядит так:
// We are in a buildForm function of a Filter-Form extending
// SymfonyComponentFormAbstractType 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();
}
/*
anyhow, we 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, // or false, but then the closure for apply_filter must be implemented in simpler way
'label' => 'Filter for related whatevers',
'required' => false,
'apply_filter' => function (QueryInterface $filterQuery, string $field, array $values): ?ConditionInterface {
if (empty($values['value'])) {
// nothing to filter here
return null;
}
// for multiple=true make sure, the $value is an ArrayCollection,
// as the ChoiceFilterType gives us a plain array
// that does not work in the LexikFormFilterBundle at least until 7.0.3
// otherwise just take that one value for multiple=false
$value = new ArrayCollection($values['value']);
$whatevers = $value->filter(function(int|string $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
$queryAlias = 'myWhatevers';
$filterQuery->getQueryBuilder()->innerJoin($field, $queryAlias);
// for multiple=false that construct can be reduced to last two variants
if ($value->contains('none')) {
if ($whatevers->count() > 0) {
// we have 'none' and at least one other value to filter for
return $filterQuery->createCondition(
$filterQuery->getExpr()->orX(
$filterQuery->getExpr()->isNull($queryAlias),
$filterQuery->getExpr()->in($queryAlias . '.id', ':p_whatevers')
),
['p_whatevers' => $whatevers],
);
}
return $filterQuery->createCondition(
// we only have 'none', so the filter is less complex
$filterQuery->getExpr()->isNull($queryAlias),
[],
);
}
return $filterQuery->createCondition(
// no 'null' selected, so we just use that standard expression for related entities
$filterQuery->getExpr()->in($queryAlias . '.id', ':p_whatevers'),
['p_whatevers' => $whatevers],
);
},
])
;
И это работает: я могу найти задачи, назначенные некоторым пользователям и / или никому не назначенные. И когда я не заполняю поле, фильтр ничего не делает.