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' ]
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 ]); }
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:
3.16.29.209