Zii grids are very useful to quickly create efficient application admin pages or any pages on which you need to manage data.
Let's use Gii to generate a grid, see how it works, and how we can customize it.
Carry out the following steps:
yiic webapp
as described in the official guide.protected/config/main.php
.customer
, address
, and city
tables.Customer
into the Model Class field. Press Preview and then Generate.protected/controllers/CustomerController.php
and a group of views under protected/views/customer/
.customer
controller and go to the Manage Customer link. After logging in you should see the grid generated, as shown in the following screenshot:Let's start with the admin
action of our customer
controller:
public function actionAdmin() { $model=new Customer('search'), $model->unsetAttributes(); // clear any default values if(isset($_GET['Customer'])) $model->attributes=$_GET['Customer']; $this->render('admin',array( 'model'=>$model, )); }
The Customer
model is created with the search
scenario, all attribute values are cleaned up, and then filled up with data from $_GET
. On the first request, $_GET
is empty but when you are changing the page, or filtering by the first_name
attribute using the input field below the column name, the following GET
parameters are passed to the same action via an AJAX request:
Customer[address_id] = Customer[customer_id] = Customer[email] = Customer[first_name] = alex Customer[last_name] = Customer[store_id] = Customer_page = 2 ajax = customer-grid
Since the scenario is search
, the corresponding validation rules from Customer::rules
are applied. For the search
scenario, Gii generates a safe rule that allows for mass assigning of all fields:
array('customer_id, store_id, first_name, last_name, email, address_id, active, create_date, last_update', 'safe', 'on'=>'search'),
Then the model is passed to a view, protected/views/customer/admin.php
. It renders an advanced search form and then passes the model to the grid widget:
<?php $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'customer-grid', 'dataProvider'=>$model->search(), 'filter'=>$model, 'columns'=>array( 'customer_id', 'store_id', 'first_name', 'last_name', 'email', 'address_id', /* 'active', 'create_date', 'last_update', */ array( 'class'=>'CButtonColumn', ), ), )); ?>
Columns used in the grid are passed to columns
. When just a name is passed, the corresponding field from the data provider is used.
Also we can use a custom column represented by a class specified. In this case we are using CButtonColumn
that renders the view, update, and delete buttons that are linked to the same named actions and pass the row ID to them, so action can be done to a model representing a specific row from the database.
The filter
property accepts a model filled with data. If it's set, a grid will display multiple text fields at the top that the user can fill to filter the grid.
The dataProvider
property takes an instance of data provider. In our case it's returned by the model's search
method:
public function search() { // Warning: Please modify the following code to remove attributes that // should not be searched. $criteria=new CDbCriteria; $criteria->compare('customer_id',$this->customer_id); $criteria->compare('store_id',$this->store_id); $criteria->compare('first_name',$this->first_name,true); $criteria->compare('last_name',$this->last_name,true); $criteria->compare('email',$this->email,true); $criteria->compare('address_id',$this->address_id); $criteria->compare('active',$this->active); $criteria->compare('create_date',$this->create_date,true); $criteria->compare('last_update',$this->last_update,true); return new CActiveDataProvider(get_class($this), array( 'criteria'=>$criteria, )); }
This method is called after the model was filled with the $_GET
data from the filtering fields, so we can use field values to form the criteria for the data provider. In this case all numeric values are compared exactly while string values are compared using partial matches.
Code generated by Gii can be useful in a lot of simple cases but often we need to customize it.
In the code, the generated grid displays the store and address IDs instead of corresponding values. Let's fix the address and display the city, district, and address instead of just the ID.
Customer
model:public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'address' => array(self::BELONGS_TO, 'Address', 'address_id'), 'store' => array(self::BELONGS_TO, 'Store', 'store_id'), 'payments' => array(self::HAS_MANY, 'Payment', 'customer_id'), 'rentals' => array(self::HAS_MANY, 'Rental', 'customer_id'), ); }
address
data along with the model. That means we have to add these to the with
part of the criteria passed to the data provider in Customer::search
. Since the address includes the city ID, we need to load the city
data using the city relation of the Address
model.public function search() { // Warning: Please modify the following code to remove //attributes that should not be searched. $criteria=new CDbCriteria; $criteria->with = array('address' => array( 'with' => 'city' )); …
protected/views/customer/admin.php
:'columns'=>array( 'customer_id', 'store_id', 'first_name', 'last_name', 'email', array( 'name'=>'address', 'value'=>'$data->address->address.", ".$data->address->city->city.", ".$data->address->district', ),
name
and setting value
to a string consisting of address, city, and district.Now check the grid. It should now list the address, city, and district in the address field, as shown in the following screenshot:
Customer::search
method we need to create a CSort
instance, configure it, and pass it to the data provider:$sort = new CSort; $sort->attributes = array( 'address' => array( 'asc' => 'address, city, district', 'desc' => 'address DESC, city DESC, district DESC', ), '*', ); return new CActiveDataProvider(get_class($this), array( 'criteria'=>$criteria, 'sort'=>$sort, ));
CSort::attributes
accepts a list of sortable attributes. We want all the Customer
attributes to be sortable so we are adding *
to the list. Additionally we are specifying SQL for both ascending and descending sorting of the address
attribute.
That's it! Sorting should work.
rules
method. Then we replace the comparison in Customer::search
:$criteria->compare('address_id',$this->address_id);
This should be replaced with:
$criteria->compare('address',$this->address,true); $criteria->compare('district',$this->address,true,"OR"); $criteria->compare('city',$this->address,true,"OR");
california
in the address filter field, the three compare
methods mentioned in the previous step will result in SQL, like the following:WHERE address LIKE '%california%' OR district LIKE '%california%' OR city LIKE '%california%'
3.133.109.30