GridView Filter on has_many

Hi all,

I have 2 models Indication has many Category (and vice versa). So there is a indication_category pivot table.

I display all indications and i am able to retreive the associated category:




    <?= GridView::widget([

        'dataProvider' => $dataProvider,

        //'formatter' => new \backend\components\SLFormatter(),

        'filterModel' => $searchModel,

        'columns' => [

            ['class' => 'yii\grid\SerialColumn'],


            'name',


            [

                'label' => 'Categories',

                'value' => function($model) {

                    $indicationCategories = IndicationCategory::find()->where(['indication_id' => $model->id])->all();

                    $html = '';

                    foreach ($indicationCategories as $indicationCategory) {

                        $html .= $indicationCategory->category->name.', ';

                    }

                    return $html;

                }

            ],

            'description:text',


            ['class' => 'yii\grid\ActionColumn'],

        ],

    ]); ?>



But I am absolutly not able to filter or sort the categories.

I try so many things according to examples i found (which are always related to one to one relationship) but i didn’t reach the target.

In my Indication model i wrote:




    /**

     * @return \yii\db\ActiveQuery

     */

    public function getRemedyIndications()

    {

        return $this->hasMany(RemedyIndication::className(), ['indication_id' => 'id']);

    }


    public function getCategories(){

        return $this->hasMany(Category::className(), ['id' => 'category_id'])->viaTable('indication_category',['indication_id' => 'id']);

    }



And I create an IndicationSearch Model:




class IndicationSearch extends Indication {


    public $categories;


    public function rules() {

        return [

            [[ 'categories'], 'safe']

        ];

    }


    public function search($params) {


        // create ActiveQuery

        $query = Indication::find();


        $query->joinWith('categories');


        $dataProvider = new ActiveDataProvider([

            'query' => $query,

            'pagination' => [

                'pageSize' => Yii::$app->params['pagination'],

            ],

        ]);




        $dataProvider->sort->attributes['categories'] = [

            'asc' => ['category.name' => SORT_ASC],

            'desc' => ['category.name' => SORT_DESC],

        ];


        if (!($this->load($params) && $this->validate())) {

            return $dataProvider;

        }


        /** Really don't know what to address here: **/

        // $query->andWhere('category.name LIKE "%' . $this->categories->name);


        return $dataProvider;

    }


}



Any help would be appreciate.

Thanks

Ok, I found the road to achieve the goal

So 3 tables Indication, indication_category and category.

In Indication Model (the "leading" Model)




    /**

     * @return \yii\db\ActiveQuery

     */

    public function getRemedyIndications()

    {

        return $this->hasMany(RemedyIndication::className(), ['indication_id' => 'id']);

    }


    public function getCategories() {

        return $this->hasMany(Category::className(), ['id' => 'category_id'])->viaTable('indication_category', ['indication_id' => 'id']);

    }

    public function getCategoryNames(){

        $cats = $this->categories;

        $categoryNames = '';

        foreach ($cats as $cat) {

            $categoryNames .= ' '.$cat->name.',';

        }


        return $categoryNames;

    }



in IndicationSearch Model




class IndicationSearch extends Indication {


    public $categoryNames;


    public function rules() {

        return [

            [[ 'categoryNames'], 'safe']

        ];

    }


    public function search($params) {


        // create ActiveQuery

        $query = Indication::find();




        $dataProvider = new ActiveDataProvider([

            'query' => $query,

            'pagination' => [

                'pageSize' => Yii::$app->params['pagination'],

            ],

        ]);


        if (!($this->load($params) && $this->validate())) {

            return $dataProvider;

        }


        /* Add your filtering criteria */


        if ( ! empty($this->categoryNames)) {

            $query->joinWith(['categories' => function ($q) {

                $q->where('category.name LIKE "%' . $this->categoryNames . '%"');

            }]);


        }


        return $dataProvider;

    }


}



in Indication Controller : just use the dataProvider and pass it to view

In index.php view of all indications




    <?= GridView::widget([

        'dataProvider' => $dataProvider,

        //'formatter' => new \backend\components\SLFormatter(),

        'filterModel' => $searchModel,

        'columns' => [

            ['class' => 'yii\grid\SerialColumn'],


            'name',

            'categoryNames',

            'description:text',


            ['class' => 'yii\grid\ActionColumn'],

        ],

    ]); ?>



And it works, I can apply filtering on the column categoryNames

have a good day