Search code examples
phpyii2yii2-basic-appyii2-model

Yii2 dataprovider with manytomany relation


I try to build a grid view with many-to-many relations. So I need a query for the ActiveDataProvider .

I have a table 'ressource', a table 'type' and between them a table 'historique'.

I have the good relation in my models but I don't know how to create the dataProvider.

In my model Ressource :

public function getHistorique()
{
    return $this->hasMany(Historique::className(), ['idType' => 'idType']);
}



public function getType()
{
     return $this->hasMany(Type::className(), ['idType' => 'idType'])
        ->viaTable(Historique::className(), ['idRessource' => 'idRessource']);   
}

In my model Historique :

public function getType()
{
    return $this->hasOne(Type::className(), ['idType' => 'idType']);
}

public function getRessource()
{
    return $this->hasOne(Ressource::className(), ['idRessource' => 'idRessource']);
}

and finally in my model Type :

public function getHistorique()
{
    return $this->hasMany(Historique::className(), ['idType' => 'idType']);
}
public function getRessource()
{
    return $this->hasMany(Ressource::className(), ['idRessource' => 'idRessource'])
        ->viaTable(Historique::className(), ['idType' => 'idType']);
}

So in the Controller (in fact my ModelSearch), I want to have ressources with type from the table historique. I don't know what I have to add after

Ressource::find();

Solution

  • I think you use RessourceSearch()->search() method. So inside it you have something like this:

    $query = Ressource::find();
    
    $dataProvider = new ActiveDataProvider([
        'query' => $query,
    ]);
    
    if (!($this->load($params) && $this->validate())) {
      return $dataProvider;
    }
    
    // Here is list of searchable fields of your model.
    $query->andFilterWhere(['like', 'username', $this->username])
          ->andFilterWhere(['like', 'auth_key', $this->auth_key])
    
    
    return $dataProvider;
    

    So, basically, you need to add additional Where you your query and force to join relation table. You can do that using joinWith method to join additional relation and andFilterWhere using table.field notation for adding filter parameters. For example:

    $query = Ressource::find();
    $query->joinWith(['historique', 'type']);
    $query->andFilterWhere(['like', 'type.type', $this->type]);
    $query->andFilterWhere(['like', 'historique.historique_field', $this->historique_field]);
    

    Also do not forget to add rules for additional filters in your search model. For example above, you should add to your rules() array something like that:

    public function rules()
        {
            return [
                // here add attributes rules from Ressource model
                [['historique_field', 'type'], 'safe'],
            ];
        }
    

    You can use any additional validation rules for that fields