Friday, December 14, 2012

Setting Up Pagination

There are a few different ways to set up pagination with CGridView and CListView that all ultimately do the same task. It is fairly easy to do when using CDataProvider to populate CGridView and CListView. Take the following example:

public function actionIndex()
{
$dataProvider=new CActiveDataProvider('NewTask', array(
'criteria'=>array(
'condition'=>'status=0',
'order'=>'import_date DESC',
),
'pagination'=>array(
'pageSize'=>5,
),
));
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
In this example the 'pagination' property of CDataProvider is used to set the page size to 5. This can be accomplished in the exact same manner however with different syntax.

public function actionProgress()
{
$dataProvider=new CActiveDataProvider('NewTask', array(
'criteria'=>array(
'condition'=>'status>0',
'order'=>'import_date ASC',
),
));
$dataProvider->pagination->pageSize=4;
$this->render('progress',array(
'dataProvider'=>$dataProvider,
));

}
In this example the 'pagination' property is set to a page size of 4. This is useful if you want to display all the items contained in the $dataProvider array. To display all items use the 'totalItemCount' property of CActiveDataProvider.
$dataProvider->pagination->pageSize=$dataProvider->totalItemCount;
What happens when CDataProvider is not obviously used as the data provider for a view? In the view called admin you may find that this is the case. Take the following example of the controller method called actionAdmin.

public function actionAdmin()
{
$model=new NewTask('search');
$model->unsetAttributes();  // clear any default values
if(isset($_GET['NewTask']))
$model->attributes=$_GET['NewTask'];

$this->render('admin',array(
'model'=>$model,
));
}

In this case the data is not being sent to the view with $dataProvider and you will notice in the admin view that CGridView will be similar to:

<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'export-task-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'id',......
The important part to notice is 'dataProvider'=>$model->search()' . To control the pagination the search function inside of the respective model needs to be changed.

public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.

$criteria=new CDbCriteria;

$criteria->compare('id',$this->id);
$criteria->compare('client_id',$this->client_id,true);
$criteria->compare('user_id',$this->user_id,true);
$criteria->compare('status',$this->status);

return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'pagination'=>array(
'pageSize'=>5,
),
));
}
}
When CActiveDataProvider is returned to the admin view the pagination will be set to 5 (as in this example).
There are also a number of properties in CGridView that are worth knowing about such as 'enableSorting', 'enablePagination', 'summaryText' and 'template' just to name a view. These properties enable you to change the behaviour and appearance of CGridView. As an example of the syntax (using TbGridview):

<?php $this->widget('bootstrap.widgets.TbGridView', array(
'type'=>'striped bordered condensed',
'id'=>'new-task-grid',
'template'=>"{items}",
'dataProvider'=>$model->search(),
'enablePagination'=>true,
 'summaryText'=>'Displaying {start}-{end} of {count} results.',
 'template' => "{summary}{items}{pager}",
'filter'=>$model,
'columns'=>array(

References:

Friday, December 7, 2012

Create Ordered Drop Down List in CGridView

In CGridView it can be really useful to have a drop down to quickly filter a list. For example you may want to create a filter based on Business Name. To quickly filter the list in CGridView adding a drop down list is an excellent option.


For the drop down to be useful often time you will need to create an ordered drop down list and using Yii's Active Record makes this fairly easy to do. Firstly the code:

<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'client-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'provider_id',
array(
'name'=>'business_name',
'filter'=>CHtml::listData(Client::model()->findAll(array('condition'=>'active=1',
'order'=>'business_name ASC')),
'business_name','business_name'), //REALLY IMPORTANT
'type'=>'raw',
'value'=>'CHtml::link($data->business_name, array("client/view","id"=>$data->id))',
'htmlOptions'=>array('width'=>'100'),
),
'business_address',
'business_suburb',
'business_postcode',
                array(
'class'=>'CButtonColumn',
),
),
)); ?>

You will notice the I have used a query to return the results to the filter and ordered the Business Name. Take note of  'business_name','business_name' - If you do not use the actual attribute name in this format you will not get the drop down list returning the correct result or the filter will not work. Do not be tempted to use 'id', 'business_name' as you would typically do as this will return a valid drop down list however the filter function will not work. If you want to add a hyperlink to the filter results then ensure you use 'type'=>'raw' (see CFormatter for more information on the various 'types' available).

Sunday, December 2, 2012

Render, Redirect and Variables with Yii

The primary purpose of a View is to display data and accessing data in the View is relatively easy. The easiest way to show how to do this is by example.

In your Controller there are various methods such as actionIndex, actionView, actionCreate etc. Let's break down a simple actionIndex for a model called Client.
public function actionIndex()
{
$dataProvider=new CActiveDataProvider('Client'); //first part
$this->render('index',array(                         //second part
'dataProvider'=>$dataProvider,                  
));
}
The first part of this method is loading data into the $dataProvider array. The second part is responsible for selecting/rendering the appropriate View and pushing the data into the View.

In the second part of the above method (the code responsible for rendering the view) you will notice the first parameter is 'index' and this is the View that will be displayed in the browser. The second parameter 'dataProvider' is the data that is sent to the View called 'index'. Lets look at the CController Class Reference and specifically the method called render().
public string render(string $view, array $data=NULL, boolean $return=false)
You will see the 'render' method takes 3 parameters - the name of the View (a string) , the data passed to the view (an array) and finally a boolean value which we won't worry about. This boolean value can be null (omitted) so it is not required. How do we access the data that is passed to the view? All we need to do is use '$data->property' where property is any of fields in the 'Client' table e.g. $data->name,
$data->address.

It is also possible to send more than one variable to the view and all you need to do is separate these variables with comma's.

public function actionIndex()
{
  $myVariable = "Hello World";
$dataProvider=new CActiveDataProvider('Client');
$this->render('index',array(                      
'dataProvider'=>$dataProvider,   'myVariable'=>$myVariable,            
));
}
To access this additional variable in the 'index' view you only need to refer to the variable name.
<?php echo "This is my variable - ".$myVariable; ?>

You will notice up until now we have been using the 'render' method of the class 'CController'. There is another method you will see in your controller called 'redirect()'. The 'redirect' method is a little different to the 'render' method in terms of how you access the data you push to the view.
public void redirect(mixed $url, boolean $terminate=true, integer $statusCode=302)
Let's just focus on the url parameter -  the documentation says basically that the url parameter can be just the URL to be redirected to OR if the parameter is an array, the first element must be a route to a controller action and the rest are GET parameters in name-value pairs. This means that when using the 'redirect' method the view can be passed to the method as an array along with any variables that need to be pushed to the view. An example of the syntax of the redirect method is:
$this->redirect(array('index','id'=>$model->id, 'myVariable'=>$myVariable,));
Notice that the view called 'index' is in an array with a variable called $myVariable which is a different syntax to the 'render' method. This is the trick - you cannot access the variable called 'myVariable' in the same way as previously with the 'render' method. As the documentation says you need to use the 'GET' method to access this variable. So in the view called 'index' you can access the variable called 'myVariable' by using the following:
<?php echo "This is my variable - ".$_GET['myVariable']; ?>
This is an important difference between the 'render' and 'redirect' method in a controller and is easy to overlook. To access variables pushed to a View, there is an important difference depending on whether the controller uses the 'render' method (in which case you access the pushed variables by the variable name) or the 'redirect' method (variables pushed to the view must be access by the GET method).

This is a good example of how important the Class Reference can be if you are having difficulty with a particular method. The reference may seem a little confusing however once you become accustomed to the syntax the explanation of the parameters can often resolve problems you may experience with a particular method.

References:

  1. Render Method
  2. Redirect Method