Displaying and filtering ActiveRecord relational data in a grid's column

Let's now focus on relational data in GridView, a common topic that is easily solved by itself.

Think about the reservations grid, which has two relational fields: room_id and customer_id, referring respectively to room and customer tables. What if we want to immediately display the customer's surname, or room number?

At this point, our goal is to display relational data, for example, the customer's surname instead of customer_id in GridView. Fields that refer to related data are expressed with the relation attribute.

In the reservation grid view, customer is the relation to get a related customer and surname is the field to keep.

Therefore, to display the customer's surname, it is enough to insert this column (as a string) in the reservations grid view:

    'customer.surname'

This is equivalent to:

    [
        'attribute' => 'customer.surname'
    ]

A column named surname will be displayed. If we want to change column name to Customer, we use this:

    [
        'header' => 'Customer',
        'attribute' => 'customer.surname'
    ]

Note

We could use custom properties to get data, for example, getnameAndSurname to get the personal details of a specific customer.

Insert a new property in the Customer model:

public function getNameAndSurname() {
     return $this->name.' '.$this->surname;
}

Then this will be the column in the GridView:

     [
        'header' => 'Customer',
        'attribute' => 'customer.nameAndSurname'
    ]

We now want to filter the Customer column. Since the customer.surname attribute is not in the rules() method of the Reservation model, we need to extend this class to handle extra attributes.

So, create a new class named ReservationSearch in basic/models/ReservationSearch.php with the following content:

<?php

class ReservationSearch extends appmodelsReservation
{
    public function attributes()
    {
        // add related fields to searchable attributes
        return array_merge(parent::attributes(), ['customer.surname']);
    }
    
    public function rules()
    {
        // add related rules to searchable attributes
        return array_merge(parent::rules(),[ ['customer.surname', 'safe'] ]);
    }    
    
}

This extension simply adds a new attribute and a new rule attached to this attribute. The name of the attribute is customer.surname.

We now have to change the actionGrid() action in ReservationsController to make a connection to the customer table that permits us to filter based on the customer's surname.

This is the content of actionGrid() of ReservationsController in basic/controllers/ReservationsController.php:

    public function actionGrid()
    {
        $query = appmodelsReservation::find();

        $searchModel = new appmodelsReservationSearch();
        if(isset($_GET['ReservationSearch']))
        {
            $searchModel->load( Yii::$app->request->get() );
            
            $query->joinWith(['customer']);
            $query->andFilterWhere(
                ['LIKE', 'customer.surname', $searchModel->getAttribute('customer.surname')]
            );
            
            $query->andFilterWhere([
                'id' => $searchModel->id,
                'customer_id' => $searchModel->customer_id,
                'room_id' => $searchModel->room_id,
                'price_per_day' => $searchModel->price_per_day,
            
            ]);
        }
        
        $dataProvider = new yiidataActiveDataProvider([
            'query' => $query,
            'pagination' => [
                'pageSize' => 10,
            ],
        ]);
        
        
        return $this->render('grid', [ 'dataProvider' => $dataProvider, 'searchModel' => $searchModel ]);
        
    }

Note

Be careful to ensure that $searchModel is instanced from the ReservationSearch class, as much as $_GET, parameter used to get data is instanced from ReservationSearch instead of Reservation (because it has changed class).

Filtering an action on the customer's surname in actionGrid() is made using these lines of code:

            $query->joinWith(['customer']);
            $query->andFilterWhere(
                ['LIKE', 'customer.surname', $searchModel->getAttribute('customer.surname')]
            );

We make a join and if the customer.surname attribute is not null, then there will be a new filter. Browse to http://hostname/basic/reservations/grid and type Fo in the Customer column filter. You should see this:

Displaying and filtering ActiveRecord relational data in a grid's column

Filtering using relational data

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.29.209