Format Gridview data

Hi everyone,

I’m just starting out with Yii, and very quickly used the command line tools to get basic CRUD working on an existing (postgres) database table from a previous project.

The default ‘admin’ action renders a nice looking Gridview object with my data in it, but it’s not formatted very well.

2 particular examples:

I have some currency fields (in the database they are type numeric(8,2)) which are currently displaying as regular numbers. How can I display them in currency format eg 23.4 -> £23.40 ?

I have some timestamps (database type is timestamp without timezone) which are being displayed like this ‘2010-01-04 15:04:53.185995’. It’s nice that the database stores it so accurately, but for presentation on an index page, something like this would be better: ‘4th Jan 2010 15:04’.

Hopefully this is pretty simple to do. Any help much appreciated.

Thanks, Dan

Check this http://www.yiiframework.com/doc/api/CFormatter

Thanks for the pointer omko.

The default CFormat class couldn’t do what I wanted though. It failed for the timestamps because the PHP date() function it’s based on expects a unix timestamp, but the database was supplying a string. There was also no way I could see to format a number for currency, so I extended the class as shown below, and edited my main.php config file to tell it to use the new DHFormatter component. Added a sterling formatter function for my currency values, and modified the date/time functions to parse string data instead of crashing.

Now the grid shows my data the way I want it. If anyone knows a better way of doing this, please say.

Cheers, Dan




<?php


class DHFormatter extends CFormatter

{


	public $showpence = true;


	public function formatSterling($value)

	{

		$num = (int)round($value * 100);

		if ($num<0) {$sign = '-'; $num = $num * -1;} else {$sign = '';}

		$pence = $num % 100; $pounds = ($num-$pence)/100;

		$left = (string)$pounds;

		if ($this->showpence) {

			$pence = (string)$pence;

			if (strlen($pence)==1) {$pence = $pence . '0';}

			$right = ".$pence";

		} else {

			$right = "";

		}

		while (strlen($left)>3) {

			$right = ',' . substr($left,-3) . $right;

			$left = substr($left,0,-3);

		}

		return ($sign=='-'?'-':'') . '£' . $left . $right;

	}


	public function formatDate($value)

	{

		if (! is_numeric($value)) {$value = strtotime($value);}

		return parent::formatDate($value);

	}


	public function formatTime($value)

	{

		if (! is_numeric($value)) {$value = strtotime($value);}

		return parent::formatTime($value);

	}


	public function formatDatetime($value)

	{

		if (! is_numeric($value)) {$value = strtotime($value);}

		return parent::formatDateTime($value);

	}




}



Hi cheeserolls,

I found your post really useful for mapping database values which are abbreviations to meaningful names. Here is an example:

protected/config/main.php:




[code]

return array(

[...]

    'components'=>array(

        'format'=>array(

            'class'=>'MyFormatter',

        ),

[...]



The custom component looks like this:

protected/components/MyFormatter.php:




<?php

/**

 * MyFormatter is the customised formatter class.

 */


class MyFormatter extends CFormatter

{

    /**

     * @var array the text to be displayed when formatting a frequency value.

     * Each key corresponds to the value that will be displayed.

     */

    public $frequencyFormat=array(

        'D'=>'Daily',

        'W'=>'Weekly',

        'M'=>'Monthly',

        'Y'=>'Yearly',

    );


   /**

     * Formats the value as a HTML-encoded frequency.

     * @param mixed the value to be formatted

     * @return string the formatted result

     */

    public function formatFrequency($value)

    {

        if(!empty($this->frequencyFormat[$value]))

            return CHtml::encode($this->frequencyFormat[$value]);

        else

            throw new CException(Yii::t('yii','Unknown frequency "{frequency}".',array('{frequency}'=>$value)));

    }

}



Finally, this is used in a widget as follows:

protected/views/myview/_something.php:




<?php $this->widget('zii.widgets.grid.CGridView', array(

    'dataProvider'=>$model,

    'columns'=>array(

        'charge_name'

        'charge_amount',

        array(

            'name'=>'charge_frequency',

            'type'=>'frequency',

            'value'=>'CHtml::encode($data->charge_frequency)',

        ),

    ),

));

?>



More to the point of your message though, I tackled the currency symbol issue as follows:

protected/config/main.php:




<?php

return array(

    [...]

    'params'=>array(

        [...]

        'currency'=>'GBP',

        ),

[...]



protected/views/myview/_detail.php:




<?php $this->widget('zii.widgets.CDetailView', array(

    'data'=>$model,

    'attributes'=>array(

        'address.address_line_1',

        'address.address_line_2',

        'address.city',

        'address.postcode',

        'property_type',

        'property_value',

        array(

            'name'=>'valuation_date',

            'type'=>'raw',

        ),

        array(

            'name'=>'rental_value',

            'type'=>'raw',

            'value'=>Yii::app()->numberFormatter->formatCurrency($model->rental_value,

                Yii::app()->params->currency),

        ),

    ),

)); ?>



Just thought I would share these alternatives with the community…

Thanks for your thoughts pmcenery.

I think there’s some merit in using the numberFormatter to display values, but I do like just being able to put things like “price:sterling” in my view code. It’s very concise and readable.

To some extent I feel that this stuff should be decided in the model. The ‘price’ field is always an amount of money, wherever it is displayed, so it would be nice to just call $model->price and know it will be currency formatted. But then you run into problems doing mathematical operations on the numbers… Not sure.

One more thing, in your view code, why not just do this:

[PHP]

<?php $this->widget(‘zii.widgets.grid.CGridView’, array(

'dataProvider'=&gt;&#036;model,


'columns'=&gt;array(


    'charge_name'


    'charge_amount',


    'charge_frequency:frequency',


),

));

?>

[/PHP]

Your format function already HTMLencodes the output, so I don’t know why you need the ‘value’ element in your array.

This is useful… thanks… :)

I know that this is an old post but I stumbled across it because I was looking to format a number into a currency. In my case Canadian dollars.




<?php

$this->widget('zii.widgets.grid.CGridView', array(

	'id'=>'membership-type-grid',

	'dataProvider'=>$model->search(),

	'filter'=>$model,

	'columns'=>array(

		'code',

		'description',

      array(

           'name'=>'fee',

           'type'=>'raw',

           'value'=>'Yii::app()->numberFormatter->formatCurrency($data->fee, "CAD")'

                                    ),

		... etc.



Just an case someone is stuck, this works.

doodle