Exebeche
@Exebeche
Осваиваю программирование

Как выводить посты из дочерних категорий в фильтре gridView/listView фреймворка Yii2?

Имеется сайт с категориями и постами. Категории могут быть очерними и родительскими по parent_id. Все прекрасно работает, за исключением одного момента с фильтрацией - при выборе в фильтре родительской категории нужно выводить посты из дочерних категорий. Долго мучился, но так и ниасилил.

Создал связь виатабле и вардампом все красиво выводится из модели, но при выборе родителя в grid/listView получю пусто-пусто

Модель Category
/**
 * @return \yii\db\ActiveQuery
 */
public function getParent()
{
    return $this->hasOne(Category::className(), ['id' => 'parent_id']);
}

/**
 * @return \yii\db\ActiveQuery
 */
public function getCategories()
{
    return $this->hasMany(Category::className(), ['parent_id' => 'id'])->with('posts');
}

/**
 * @return \yii\db\ActiveQuery
 */
public function getPost()
{
    return $this->hasMany(Post::className(), ['category_id' => 'id']);
}

public function getChildrenPosts()
{
    return $this->hasMany(Post::className(), ['category_id' => 'id'])->indexBy('id')->asArray()->viaTable('{{%category}}', ['parent_id' =>'id']);
}


Модель Post
/**
 * @return \yii\db\ActiveQuery
 */
public function getCategory()
{
    return $this->hasOne(Category::className(), ['id' => 'category_id']);
}

public function getChildrenPosts()
{
    return $this->hasMany(Post::className(), ['category_id' => 'id'])->indexBy('id')->asArray()->viaTable('{{%category}}', ['parent_id' =>'id']);
}


Модель PostSearch

public function search($params)
{
    $query = Post::find()->with(['category', 'childrenPosts']);

    // add conditions that should always apply here

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

    $this->load($params);

    if (!$this->validate()) {
        // uncomment the following line if you do not want to return any records when validation fails
        // $query->where('0=1');
        return $dataProvider;
    }

    // grid filtering conditions
    $query->andFilterWhere([
        'id' => $this->id,
        'category_id' => $this->category_id,
        'content' => $this->content,
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ]);

    return $dataProvider;
}


Модель CategorySearch

public function search($params)
{
    $query = Category::find()
        ->select(['{{%category}}.*', 'posts_count' => new Expression('COUNT({{%post}}.id)')])
        ->joinWith(['post'], false)
        ->groupBy('{{%category}}.id')
        ->with(['parent', 'childrenPosts']);

    // add conditions that should always apply here

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

    $this->load($params);

    if (!$this->validate()) {
        // uncomment the following line if you do not want to return any records when validation fails
        // $query->where('0=1');
        return $dataProvider;
    }

    // grid filtering conditions
    $query->andFilterWhere([
        'id' => $this->id,
        'parent_id' => $this->parent_id,
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ]);

    return $dataProvider;
}


Как видно из кода - пытался изо всех сил пристроить childrenPosts, но все без успешно. Пожалуйста, подскажите, что я где не так и объясните, пожалуйста, как нужно сделать чтобы было правильно.

З.Ы. Желательно своими словами т.к.прочитанное и просмотренное ранее не принесло результата :( Получил ответ от Дмитрия Елисеева:
if (!empty($this->category_id)) {
$ids = [$this->category_id];
$childrenIds = $ids;
while ($childrenIds = Category::find()->select('id')->andWhere(['parent_id' => $childrenIds])->column()) {
    $ids = array_merge($ids, $childrenIds);
}
$query->andWhere(['category_id' => array_unique($ids)]);
}


Но как не пытался его вставить, модернизировать никакого результата.
Очень нужно разобраться
  • Вопрос задан
  • 299 просмотров
Решения вопроса 1
Exebeche
@Exebeche Автор вопроса
Осваиваю программирование
Помогли решить на воркзиле
public function search($params)
    {
        $query = Product::find()
            ->from(['p' => Product::tableName()])
            ->with(['designer', 'category']);

        // add conditions that should always apply here

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

        $this->load($params);

        if (!$this->validate()) {
            // uncomment the following line if you do not want to return any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }

        // grid filtering conditions
        $query->andFilterWhere([
            'p.id' => $this->id,
            //'p.category_id' => $this->category_id,
            'p.designer_id' => $this->designer_id,
            'p.price' => $this->price,
            'p.new' => $this->new,
            'p.hit' => $this->hit,
            'p.sale' => $this->sale,
            'p.created_at' => $this->created_at,
            'p.updated_at' => $this->updated_at,
//            'p2.childrenProducts' => $this->category_id
        ]);

        if (!empty($this->category_id)) {
            $ids = Category::find()->andWhere(['parent_id'=>[$this->category_id]])->alias('p2')->column();
            $ids[] = $this->category_id;
            $query->andWhere(['p.category_id' => array_unique($ids)]);
    }

        $query->andFilterWhere(['like', 'title', $this->title])
            ->andFilterWhere(['like', 'art', $this->art])
            ->andFilterWhere(['like', 'meta_key', $this->meta_key])
            ->andFilterWhere(['like', 'meta_description', $this->meta_description])
            ->andFilterWhere(['like', 'description', $this->description])
            ->andFilterWhere(['like', 'image_alt', $this->image_alt]);

        return $dataProvider;
    }
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
webinar
@webinar Куратор тега Yii
Учим yii: https://youtu.be/-WRMlGHLgRg
Вместо
$query = Post::find()->with
видимо надо
$query = Post::find()->joinWith
Так как Вам не жадная загрузка отдельным запросов нужна, а join
Ответ написан
Ваш ответ на вопрос

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

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