phpactiverecordyii2many-to-manycactivedataprovider

Many-to-many relation in yii2 activedataprovider


I have many-to-many relation with three tables: Category, Product, ProductCategory. Relation in Category:

public function getProductCategories()
{
    return $this->hasMany(ProductCategory::className(), ['category_id' => 'id']);
}

Relation in Product:

    public function getProductCategories()
{
    return $this->hasMany(ProductCategory::ClassName(), ['product_id' => 'id']);
}

And in ProductCategory

public function getProduct()
{
    return $this->hasOne(Product::className(), ['id' => 'product_id']);
}

public function getCategory()
{
    return $this->hasOne(Category::className(), ['id' => 'category_id']);
}

In my Category Controller I used this code to show the products I need according to their category (one-to-many):

    $cats = Category::findOne(['slug1'=>$slug1]);
    $dataProvider = new ActiveDataProvider([

        'query' => $query = Product::find()->where(['category_id' => $cats->id]),
        'sort'=>array(
            'defaultOrder'=>['id' => SORT_ASC],
        ),
        'pagination' => [
            'pageSize' => 9,
        ],
    ]);

So the question is how to make my ActiveDataProvider to get in query the many-to-many relation?


Solution

  • You can create two more relations like this

    In category:

    public function getProducts()
    {
       return $this->hasMany(Product::className(), ['id' =>   'product_id'])->via("productCategories");
    }
    

    And in product:

    public function getCategories()
    {
      return $this->hasMany(Category::ClassName(), ['id' =>   'category_id'])->via("productCategories");
    }
    

    Then you can use it like this

    $cats = Category::findOne(['slug1'=>$slug1]);
    $dataProvider = new ActiveDataProvider([
    
        'query' => $query = $cats->getProducts(),
        'sort'=>array(
            'defaultOrder'=>['id' => SORT_ASC],
        ),
        'pagination' => [
            'pageSize' => 9,
        ],
    ]);