Skip to main content

Yii 2.0: Displaying, Sorting and Filtering Model Relations on a GridView, Gridview with relationships

One of the things you will find tricky to implement is the the sorting and filtering of a GridView's column that displays related model data.
As you know if you have been playing with Yii2 lately, there is a new proposed way to search for data and is by using objects that extend from the main entity models and mark the searchable attributes as "safe". So, how do we sort and filter related data on a GridView widget?
Lets imagine we have the following relations of a model named "Tour":
/**
 * @return \yii\db\ActiveQuery
 */
public function getCountry()
{
    return $this->hasOne(Country::className(), ['id' => 'country_id']);
}
 
/**
 * @return \yii\db\ActiveQuery
 */
public function getCity()
{
    return $this->hasOne(City::className(), ['id' => 'city_id']);
}
And we wish to display the name of the country and the name of the city on a GridView. To do that, we do the following on our "TourSearch" model:
class TourSearch extends Tour // extends from Tour see?
{
    // add the public attributes that will be used to store the data to be search
    public $city;
    public $country;
 
    // now set the rules to make those attributes safe
    public function rules()
    {
        return [
            // ... more stuff here
            [['city', 'country'], 'safe'],
            // ... more stuff here
        ];
    }
// ... model continues here
Now we will be able to setup our GridView so to display the related data:
// ... more grid configuration here
 'columns' => [
 // ... more columns configuration here
 [
 'attribute' => 'city',
 'value' => 'city.name'
 ],
 [
 'attribute' => 'country',
 'value' => 'country.name'
 ],
 // ... more stuff here
By doing as explained above, we will be able to display data but how to sort or filter? Lets explain that by example, and this time lets focus on the "search" method of our "TourSearch" class:
public function search($params)
{
    // create ActiveQuery
    $query = Tour::find();
    // Important: lets join the query with our previously mentioned relations
    // I do not make any other configuration like aliases or whatever, feel free
    // to investigate that your self
    $query->joinWith(['city', 'country']);
 
    $dataProvider = new ActiveDataProvider([
        'query' => $query,
    ]);
 
    // Important: here is how we set up the sorting
    // The key is the attribute name on our "TourSearch" instance
    $dataProvider->sort->attributes['city'] = [
        // The tables are the ones our relation are configured to
        // in my case they are prefixed with "tbl_"
        'asc' => ['tbl_city.name' => SORT_ASC],
        'desc' => ['tbl_city.name' => SORT_DESC],
    ];
    // Lets do the same with country now
    $dataProvider->sort->attributes['country'] = [
        'asc' => ['tbl_country.name' => SORT_ASC],
        'desc' => ['tbl_country.name' => SORT_DESC],
    ];
    // No search? Then return data Provider
    if (!($this->load($params) && $this->validate())) {
        return $dataProvider;
    }
    // We have to do some search... Lets do some magic
    $query->andFilterWhere([
        //... other searched attributes here
    ])
    // Here we search the attributes of our relations using our previously configured
    // ones in "TourSearch"
    ->andFilterWhere(['like', 'tbl_city.name', $this->city])
    ->andFilterWhere(['like', 'tbl_country.name', $this->country]);
 
    return $dataProvider;
}
Thats it... Hope this tutorial helps you find your way around.

Popular posts from this blog

Yii, return to previous url after login or logout

If you want to return to your previous url after login or logout try this : <?php $this -> redirect (Yii :: app () -> request -> urlReferrer ); ?> To set the return url to be the url that was before the login page or registeration page was called you can put following code in views/layouts/main.php file : <?php //this checks id the controller action is not 'login' then it keeps the current url in returnUrl if (CController :: getAction () -> id != 'login' ) { Yii :: app () -> user -> setReturnUrl (Yii :: app () -> request -> getUrl ()); } ?>

Yii2: Using csrf token

Yii2: Using csrf token First, if you do not understand what is the CSRF token? and why should we use it, please refer to the following link : https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) One of the new features of Yii2 is CSRF validation enabled by default. If you use ajax or basic form as follows : <form action='#' method='POST'> ........... </form> You will get an error exception : Bad Request (#400): Unable to verify your data submission That is because you do not submit csrf token. The easiest way if you dont care about csrf just disable it in main config : 'components' => [ 'request' => [ .... 'enableCsrfValidation'=>false, ], ..... ], Or in Controller : public function beforeAction($action) { $this->enableCsrfValidation = false; return parent::beforeAction($action); } So how to use Csrf Validation for your strong security website: * Wi