Justique
@Justique

Yii2 filter выбор только имеющих набор опций?

Добрый день, при реализации фильтра объектов столкнулся с такой проблемой.
За основу взял yii2-filter
Суть проблемы: Имеется фильтр/опция тип чекбокс
spoiler
5c6d268e34bc9734918172.png


Работает по принципу фильтра объекта если в нём присутствует хотя бы одна из опций.
Выглядит всё это так (где item_id = id фильтруемого объекта)
ActiveRecord
$filtered = FilterValue::find()->select('item_id')->groupBy('item_id')->andHaving("COUNT(DISTINCT `filter_id`) = $variantCount")->andFilterWhere($condition);

RawSql
SELECT `item_id` FROM `filter_value` WHERE (`filter_id`=2) AND (`variant_id` IN ('8', '12')) GROUP BY `item_id` HAVING COUNT(DISTINCT `filter_id`) = 1



Получается так, что если у объекта имеется хотя бы одна опция из этого фильтра, то он попадёт в результат выборки.
Нужно же что бы результаты выборки item_id выдавался только тех у кого присутствуют все выбранные варианты, в данном случае 8, 12.

Из того что приходит на ум это только такой вариант, но он мне не нравится.
RawSql
SELECT *, GROUP_CONCAT(variant_id) AS variant_ids FROM filter_value GROUP BY item_id HAVING LOCATE('8', variant_ids) AND LOCATE('12', variant_ids)

функция filtered вызываемая через behavior модели
public function filtered($filterIds = false, $mode = 0)
    {
        if(!$filterIds) {
            $filterIds = Yii::$app->request->get($this->fieldName);
        }

        if(empty($filterIds)) {
            return $this->owner;
        }

        $condition = ['OR'];
        $variantCount = 0;
        $filterCount = count($filterIds);

        foreach($filterIds as $filterId => $value) {
            $filter = Filter::findOne($filterId);
            if($filter->type == 'range' && is_string($value)) {
                $value = explode(';', $value);
                if($value[0] != $value[1]) {
                    $variants = FilterVariant::find()->where('filter_id = :filterId AND (numeric_value >= :min AND numeric_value <= :max)', [':filterId' => $filterId, ':min' => $value[0], ':max' => $value[1]])->select('id')->all();
                } else {
                    $variants = FilterVariant::find()->where('filter_id = :filterId AND numeric_value = :value', [':filterId' => $filterId, ':value' => $value[0]])->select('id')->all();
                }
                $variantIds = ArrayHelper::map($variants, 'id', 'id');
            } else {
                $variantIds = $value;
            }
            
            $condition[] = ['filter_id' => $filterId, 'variant_id' => $variantIds];

            if($mode == 1) {
                $variantCount += count($variantIds);
            } else {
                $variantCount++;
            }
            
        }
        $filtered = FilterValue::find()->select('item_id')->groupBy('item_id')->andHaving("COUNT(DISTINCT `filter_id`) = $variantCount")->andFilterWhere($condition);
       
        $modelClass = $this->owner->modelClass;
        $tableName = $modelClass::tableName();

        if ($filtered->count() > 0) {
            $this->owner->andWhere([$tableName . '.id' => $filtered]);
        } else {
            $this->owner->andWhere([$tableName . '.id' => 0]);
        }

        return $this->owner;
    }
  • Вопрос задан
  • 86 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы