Head-Hunter
@Head-Hunter

YII2 Сложный запрос с выборкой?

День добрый форумчане, долго пинаю фильтр поиска рецептов? и что то уже кончились идеи, как это дело допинать, а дело вот в чем.
Есть табличка рецептов
id | title ...
Есть табличка продуктов
id | title ...
Есть табличка ингридиентов рецепта - это связывающая таблица Рецептов и Продуктов
id | recept_id | product_id ...
1 | 1 | 3
2 | 1 | 6
3 | 1 | 10
4 | 2 | 13
5 | 2 | 65
6 | 2 | 104

так вот как лучше написать запрос исключающий рецепт с указанным ингредиентом из поиска
вариант с joinWith как надо не работает
public function search($params, $category = null)
    {
        // $recept_ingr_query = ReceptIngredients::find();
        $ingr = false;
        $this->load($params);

        if($this->i_add_id) {
            $model = Product::findOne($this->i_add_id);
            $this->_add_filter_text = $model->title2;

            // $recept_ingr_query->andWhere(['product_id' => $this->i_add_id]);
            $ingr = true;
        }
        if($this->i_rem_id) {
            $model = Product::findOne($this->i_rem_id);
            $this->_rem_filter_text = $model->title3;

            // $recept_ingr_query->andWhere(['<>', 'product_id', $this->i_rem_id]);
            $ingr = true;
        }

        $query = Recept::find()
            ->joinWith([
                'receptIngridientLists' => function (Query $q) {
                    if($this->i_add_id) {
                        $q->andWhere([ReceptIngredients::tableName().'.product_id' => $this->i_add_id]);
                    }
                    if($this->i_rem_id) {
                        $q->andWhere(['<>', ReceptIngredients::tableName().'.product_id', $this->i_rem_id]);
                    }
                    if($this->i_add_id || $this->i_rem_id) {
                        // $q->groupBy('recept_id');
                    }
                }
            ])
            ->with(
                'category.children',
                'author',
                // 'receptIngridientLists',
                'receptDescriptionLists',
                'cooking',
                'counter'
            )
            // ->groupBy(ReceptIngredients::tableName().'.recept_id')
            ->active();

        if($category) {
            $query->andWhere(['category_id' => $category->id]);
        }

/* // - этот закоменированный вариан не рассматриваю - подход не правильный 
        if ($ingr) {
            $data = $recept_ingr_query
                ->asArray()
                ->groupBy('recept_id')
                ->indexBy('recept_id')
                ->all();
            $query->andWhere(['id' => array_keys($data)]); // при таком раскладе тут будет километр id - не есть good
        }
*/
.......... 
// тут полезная часть кода )
}
  • Вопрос задан
  • 472 просмотра
Пригласить эксперта
Ответы на вопрос 2
orlov0562
@orlov0562 Куратор тега PHP
I'm cool!
createCommand и обычный sql, типа того

SELECT * FROM recept WHERE recept_id IN (
    SELECT DISTINCT recept_id FROM recept_product WHERE
        product_id NOT IN (1,2,3)
)
Ответ написан
Комментировать
bagiroff777
@bagiroff777
Веб-разработчик
Может, попробуете relations Yii2?
В модели продуктов можно прописать связь (Relation) через связующую таблицу:
// Устанавливаем связь модели "Recipes" (Рецепты) с моделью "Products" (Продукты) с помощью связующей таблицы "recipes_products":
    public function getProducts(){
        // hasMany() устанавливает "множественную" связь, т.е. один ко многим.
        return $this->hasMany(Products::className(), ['id' => 'product_id'])->viaTable('recipes_products', ['recipe_id' => 'id']);
    }


А в модели поиска просто:
public function search($params)
    {
        $query = Recipes::find();

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);

        $this->load($params);

        if (!$this->validate()) {
        // Не возвращаем ничего в случае, если валидация не прошла
            // $query->where('0=1');

            return $dataProvider;
        }

        // Аналогично LEFT JOIN, только немного иное.
        $query->joinWith('products');

        $query->andFilterWhere(['NOT IN', 'recipes_products.product_id'/* связующая таблица */, $this->product_exclude/* массив id исключаемых продуктов */]);

// Здесь добавляем другие необходимые параметры поиска, например : $query->andFilterWhere(['products.id' => $this->product_id]);

        return $dataProvider;
    }


Но, кажется, я вас не полностью понял
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы