[EXTENSION]eexcelview

phreak,

This is truly a powerful and awesome extension! I can whip up spreadsheets for my customers in no time. But now I need to take it to the next level and add formatting to the cells. But I just can’t figure out how to do this with the information you’ve provided. Would it be possible to give a more detailed explanation?

I found section 4.6.18 FORMATTING CELLS in the document PHPExcel Developer Documentation, but I don’t understand how that applies when building a Yii application.

And I’m very familiar with passing $data to a callback, I do this all the time in my CGridViews. But how does that work with your onRenderDataCell() function?

Maybe you could provide the code for a simple example. Suppose I wanted to format all the cells in one row with a light grey background, and then format all the cells in a second row with red text in a bold font. How would you do this?

Thanks for your help. I truly appreciate your great extension as well as your time and effort supporting those of us who use it.

Bob Humphrey

Well OK :) I’ve created a small example for you :

In you controller:


	public function actionIndex()

	{

		$rawData=array(

           array('id'=>1, 'username'=>'from', 'email'=>'array'),

           array('id'=>2, 'username'=>'test 2', 'email'=>'hello@example.com'),

       );

       $data = new CArrayDataProvider($rawData);

	   $this->render('index', compact('data'));

	}

    

    public function onRenderHeaderCell(PHPExcel_Cell $cell, $value)

    {

        $worksheet = $cell->getParent();

        $worksheet->getStyle($cell->getCoordinate())->getFont()->setBold(true);

        if($value == 'email')

            $worksheet->getStyle($cell->getCoordinate())->getFont()->setItalic(true);

        

    }

In you view:


<?php 

    $this->widget('ext.EExcelView', array(

        'dataProvider'=>$data,

        'template'=>"{summary}\n{items}\n{exportbuttons}\n{pager}",

        'onRenderHeaderCell'=>array($this, 'onRenderHeaderCell'),

    ));

?>

So now you have all headers bold and the “email” is bold and italic :)

Have fun !

Hi, rikim1228

Yes this are export buttons which extend the CGridView adding export functionality. They are customized via arrays of options(see exportButtonsCSS, exportButtons, exportText

Example: …‘exportButtons’ => array(‘Excel5’=>array(‘caption’=>’*.xls’))…

By default they are disabled because they extend the cgridview so it should act as it by default. If you want to place the buttons in the view, you should modify the "template" property of the grid.

Example: … ‘template’=>"{summary}\n{items}\n{exportbuttons}\n{pager}" …

@phreak I really loved your extension (v0.33), and I played with it for a real use case, and I came up at the end with some additional properties, mainly for document properties and basic formatting (cell and numbers formatting).

It’s not supposed to cover all use cases of course, and I’m sure it’s far from perfect, but it may help someone, or not :)

Silly me, I’ve stopped in the second page, and I’ve seen in this fourth page how onRender…() methods are intended to be used, but I believe it’s easier for me to just provide simple formatting settings.

Features: automatic (and overridable) formatting of header, body and footer, automatic formatting of numbers, automatic sum in the footer, automatic page formatting (with page header and footer, automatic print area…). Nearly all properties can be overridden.

Anyway, here’s attached the resulting code (I’ve also used some improvements suggested by zenbaku’s version).

An example of use:


$this->widget('application.components.widgets.EExcelView', array(

    'id'                   => 'some-grid',

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

    'grid_mode'            => $production, // Same usage as EExcelView v0.33

    //'template'           => "{summary}\n{items}\n{exportbuttons}\n{pager}",

    'title'                => 'Some title - ' . date('d-m-Y - H-i-s'),

    'creator'              => 'Your Name',

    'subject'              => mb_convert_encoding('Something important with a date in French: ' . utf8_encode(strftime('%e %B %Y')), 'ISO-8859-1', 'UTF-8'),

    'description'          => mb_convert_encoding('Etat de production généré à la demande par l\'administrateur (some text in French).', 'ISO-8859-1', 'UTF-8'),

    'lastModifiedBy'       => 'Some Name',

    'sheetTitle'           => 'Report on ' . date('m-d-Y H-i'),

    'keywords'             => '',

    'category'             => '',

    'landscapeDisplay'     => true, // Default: false

    'A4'                   => true, // Default: false - ie : Letter (PHPExcel default)

    'pageFooterText'       => '&RThis is page no. &P of &N pages', // Default: '&RPage &P of &N'

    'automaticSum'         => true, // Default: false

    'decimalSeparator'     => ',', // Default: '.'

    'thousandsSeparator'   => '.', // Default: ','

    //'displayZeros'       => false,

    //'zeroPlaceholder'    => '-',

    'sumLabel'             => 'Column totals:', // Default: 'Totals'

    'borderColor'          => '00FF00', // Default: '000000'

    'bgColor'              => 'FFFF00', // Default: 'FFFFFF'

    'textColor'            => 'FF0000', // Default: '000000'

    'rowHeight'            => 45, // Default: 15

    'headerBorderColor'    => 'FF0000', // Default: '000000'

    'headerBgColor'        => 'CCCCCC', // Default: 'CCCCCC'

    'headerTextColor'      => '0000FF', // Default: '000000'

    'headerHeight'         => 10, // Default: 20

    'footerBorderColor'    => '0000FF', // Default: '000000'

    'footerBgColor'        => '00FFCC', // Default: 'FFFFCC'

    'footerTextColor'      => 'FF00FF', // Default: '0000FF'

    'footerHeight'         => 50, // Default: 20

    'columns'              => $grid // an array of your CGridColumns

)); ?>

By the way, this is how I used EExcelView in the controller and view:

  • Controller

    public function actionAdmin() {

        $model = new Model('search');

        $model->unsetAttributes();

        if (isset($_GET['Model'])) {

            $model->attributes = $_GET['Model'];

        }

        if (isset($_GET['export'])) {

            $production = 'export';

        } else {

            $production = 'grid';

        }

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

    }

  • _search view

Yii::app()->clientScript->registerScript('search', "

$('#exportToExcel').click(function(){

    window.location = '". $this->createUrl('admin')  . "?' + $(this).parents('form').serialize() + '&export=true';

    return false;

});

$('.search-form form').submit(function(){

    $.fn.yiiGridView.update('some-grid', {

        data: $(this).serialize()

    });

    return false;

});

"); ?>

…

$form = $this->beginWidget('GxActiveForm', array(

    'action' => Yii::app()->createUrl($this->route),

    'method' => 'get',

)); ?>

…

    <div class="row buttons">

        <?php echo GxHtml::submitButton(Yii::t('app', 'Search')); ?>

        <?php echo GxHtml::button(Yii::t('app', 'Export to Excel (xls)'), array('id' => 'exportToExcel')); ?>

    </div>

<?php $this->endWidget(); ?>

I’m using Giix / GxActiveForm but should be the same with Gii / CActiveForm

Dear All,

Is there any tutorial to create multiple sheets excel export using eexcelview?

Cheers,

Daniel

@bennouna: thanx for the contribution, I’ve been busy lately but will surely include this in the next version.

@Daniel: Currently you cannot create multiple sheets. And I cant think of a case when the grid will “know” that a second sheet is needed. Can you tell me what’s the case where you want another sheet, and what do you except to see there?

Hi phreak,

I have a sales report and it can be filtered by the salesman who made the sales. If no filter applied to the salesman, I want it to be exported to excel so that one sheet will have all sales for one salesman, rather than all sales for all salesman in one sheet, and if possible one summary sheet. So, if I have 5 salesman, I would have 6 sheets where one sheet for each salesman sales and 1 summary sheet that display the total sales of each salesman and grand total.

I understand that it may require direct coding with PHPExcel, but it is quite long compare to using eexcelview, which is more clean and easy to manage.

Cheers,

Daniel

In fact it doesn’t seem that hard with PHPExcel. You may want to see here:

I don’t know phreak’s roadmap for EExcelView, but there’s some general logic helping to automatically split your data by a filter like your use case:

  • Without too much change, the data provider has to set the filtering column (salesman) as the priority order.

  • Then that column would be parsed first by the widget, and each time its value changes, it generates a new worksheet.

Or maybe a more general solution would be to define several data providers and as many grids, and add some property to say that these grids should be separate worksheets in the same workbook?

Thank you for your reply bennouna.

I was wondering, is that possible to write/edit the already generated file using eexcelview? What happened when we write output the same file?

Cheers,

Daniel

Well, the next step on my “roadmap” is to be able to provide some styling to the report and also(which seems the harder) some sort of templating the export - to look like invoice , or to have site’s logo or smthing. But stil I have no Idea how, except manipulationg the PHPExcell object manually.

I’ll soon put the extension on github so anyone can help improve it. ;)

I’m curious why you would export an invoice to Excel? I prefer rendering a PDF, especially that I can setup the header and footer beforehand.

As for the images, it seems rather straightforward with PHPExcel, quoting from the 1.7.7 documentation:

EExcelView is on github - https://github.com/phreakbg/EExcelView

hii friends I want an example that I can export some values from a model to excel sheet using eexcelview,please provide me

I really dont know how to implement the extension codes. Can someone help by showing me how to do it… Ive downloaded the eexcelview.php, eexcelbehavior.php and the phpexcel… im confused now…

this is my controller




<?php


class MemberController extends Controller

{

	/**

	 * @var string the default layout for the views. Defaults to '//layouts/column2', meaning

	 * using two-column layout. See 'protected/views/layouts/column2.php'.

	 */

	public $layout='//layouts/column2';


	/**

	 * @return array action filters

	 */

	public function filters()

	{

		return array(

			'accessControl', // perform access control for CRUD operations

		);

	}


	/**

	 * Specifies the access control rules.

	 * This method is used by the 'accessControl' filter.

	 * @return array access control rules

	 */

	public function accessRules()

	{

				return array(

			array('allow', // allow admin user to perform 'admin' and 'delete' actions

				'actions'=>array('admin','view','loadImage'),

					'users'=>array(@AuthorizationController::getRights('member', 'canview')),

			),

				array('allow', // allow admin user to perform 'admin' and 'delete' actions

				'actions'=>array('create'),

					'users'=>array(@AuthorizationController::getRights('member', 'cancreate')),

			),

			array('allow', // allow admin user to perform 'admin' and 'delete' actions

				'actions'=>array('delete'),

				'users'=>array(@AuthorizationController::getRights('member', 'candelete')),

			),

				array('allow', // allow admin user to perform 'admin' and 'delete' actions

				'actions'=>array('update'),

					'users'=>array(@AuthorizationController::getRights('member', 'canupdate')),

			),

			array('deny',  // deny all users

				'users'=>array('*'),

			),

		);

	}

    

    

	/**

	 * Displays a particular model.

	 * @param integer $id the ID of the model to be displayed

	 */

	public function actionView($id)

	{

		$this->render('view',array(

			'model'=>$this->loadModel($id),

		));

	}


	/**

	 * Creates a new model.

	 * If creation is successful, the browser will be redirected to the 'view' page.

	 */

	public function actionCreate()

	{

		$model=new member;


		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['member']))

		{ 

            		  

			$model->attributes=$_POST['member'];

            

        /*    

		 if(!empty($_FILES['member']['tmp_name']['binaryfile']))

            {

            	

                $file = CUploadedFile::getInstance($model,'binaryfile');

                $model->filename = $file->name;

                $model->filetype = $file->type;

                $fp = fopen($file->tempName, 'r');

                $content = fread($fp, filesize($file->tempName));

                fclose($fp);

                $model->binaryfile = $content;

           

            }*/

            

            

            if($model->save())

            {

                $this->redirect(array('view','id'=>$model->id));

            }

		}


		$this->render('create',array(

			'model'=>$model,

		));

	}

        


	/**

	 * Updates a particular model.

	 * If update is successful, the browser will be redirected to the 'view' page.

	 * @param integer $id the ID of the model to be updated

	 */

	public function actionUpdate($id)

	{  

		$model=$this->loadModel($id);

		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['member']))

		{	  		  

			$model->attributes=$_POST['member'];

			

			 ///$file = CUploadedFile::getInstance($model,'binaryfile');

		     //$model->remark = $file;

				 

            // if(!empty($_FILES['member']['tmp_name']['binaryfile']))

           // {

                //$file = CUploadedFile::getInstance($model,'binaryfile');

				

           /* 	if( $file !== null )

            	{

                $model->filename = $file->name;

                $model->filetype = $file;

                $fp = fopen($file->tempName, 'r');

                $content = fread($fp, filesize($file->tempName));

                fclose($fp);

                $model->binaryfile = $content;

            	}*/

           // }

 

           // $model->user = Yii::app()->user->id;

            if($model->save())

            {   	

                $this->redirect(array('view','id'=>$model->id));

            }

        }


		$this->render('update',array(

			'model'=>$model,

		));

	}

    




	/**

	 * Deletes a particular model.

	 * If deletion is successful, the browser will be redirected to the 'admin' page.

	 * @param integer $id the ID of the model to be deleted

	 */

	public function actionDelete($id)

	{

		if(Yii::app()->request->isPostRequest)

		{

			// we only allow deletion via POST request

			$this->loadModel($id)->delete();


			// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser

			if(!isset($_GET['ajax']))

				$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));

		}

		else

			throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');

	}


	/**

	 * Lists all models.

	 */

	public function actionIndex()

	{

		$dataProvider=new CActiveDataProvider('member');

		$this->render('index',array(

			'dataProvider'=>$dataProvider,

		));

	}


	/**

	 * Manages all models.

	 */

	public function actionAdmin()

	{

		$model=new member('search');

		$model->unsetAttributes();  // clear any default values

		if(isset($_GET['member']))

			$model->attributes=$_GET['member'];


		$this->render('admin',array(

			'model'=>$model,

		));

	}


	/**

	 * Returns the data model based on the primary key given in the GET variable.

	 * If the data model is not found, an HTTP exception will be raised.

	 * @param integer the ID of the model to be loaded

	 */

	public function loadModel($id)

	{

		$model=member::model()->findByPk($id);

		if($model===null)

			throw new CHttpException(404,'The requested page does not exist.');

		return $model;

	}


	/**

	 * Performs the AJAX validation.

	 * @param CModel the model to be validated

	 */

	protected function performAjaxValidation($model)

	{

		if(isset($_POST['ajax']) && $_POST['ajax']==='member-form')

		{

			echo CActiveForm::validate($model);

			Yii::app()->end();

		}

	}

	

	public function actionloadImage($id)

    {

        $model=$this->loadModel($id);

        $this->renderPartial('picture', array(

            'model'=>$model

        ));

    }

    

    

}




and this is my admin page




<?php

$this->breadcrumbs=array(

	'Member Profile',

	'Manage Member',

);


$this->menu=array(

	//array('label'=>'List member', 'url'=>array('index')),

	array('label'=>'Create Member', 'url'=>array('create')),

);


Yii::app()->clientScript->registerScript('search', "

$('.search-button').click(function(){

	$('.search-form').toggle();

	return false;

});

$('.search-form form').submit(function(){

	$.fn.yiiGridView.update('member-grid', {

		data: $(this).serialize()

	});

	return false;

});

");

?>


<h1>Manage Members</h1>


<p>

You may optionally enter a comparison operator (<b>&lt;</b>, <b>&lt;=</b>, <b>&gt;</b>, <b>&gt;=</b>, <b>&lt;&gt;</b>

or <b>=</b>) at the beginning of each of your search values to specify how the comparison should be done.

</p>


<?php echo CHtml::link('Advanced Search','#',array('class'=>'search-button')); ?>

<div class="search-form" style="display:none">

<?php $this->renderPartial('_search',array(

	'model'=>$model,

)); ?>

</div><!-- search-form -->







<?php 




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

	'id'=>'member-grid',

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

	'filter'=>$model,

	'columns'=>array(

  

  //'eno',

       // array( 'name'=>'membertypeid', 'value'=>'$data->membertype->code', 'htmlOptions'=>array('width'=>'40px'), ),

        	 array( 'name'=>'membertypeid',  

        	  'value'=>'$data->membertype->code',

			//'value' => '$data->ismassbilling?Yii::t(\'app\',\'Yes\'):Yii::t(\'app\', \'No\')',

			'filter' => array('AF' => Yii::t('app', 'AF'), 'CREN' => Yii::t('app', 'CR'),'OM' => Yii::t('app', 'OM')),

			'htmlOptions'=>array('width'=>'80px'), ),  

        array( 'name'=>'membercode', 'value'=>'$data->membercode', 'htmlOptions'=>array('width'=>'70px'), ),

        

        

        

        

        array( 'name'=>'name', 'value'=>'$data->name', 'htmlOptions'=>array('width'=>'200px'), ),

          array( 'name'=>'icno', 'value'=>'$data->icno', 'htmlOptions'=>array('width'=>'150px'), ),

        //'passportno',

		

		  array( 'name'=>'state', 'value'=>'$data->state','htmlOptions'=>array('width'=>'50px'), ), 

        array( 'name'=>'companyid', 'value'=>'$data->company->companyname','htmlOptions'=>array('width'=>'120px'), ), 

      //  array( 'name'=>'statusid', 'value'=>'$data->status->statusid', ), 

			  array( 'name'=>'statusid', 'value'=>'$data->status->description','htmlOptions'=>array('width'=>'50px'), ), 

		/*

        'id',

		'joineddate',

		'address1',

		'address2',

		'postcode',

		'city',

		'country',

		'mobile1',

		'mobile2',

		'mobile3',

		'tel1',

		'tel2',

		'tel3',

		'fax1',

		'fax2',

		'fax3',

		'email1',

		'email2',

		'email3',

		'remark',

		'picture',

		'createdby',

		'createddate',

		'modifiedby',

		'modifieddate',

		*/

		array

(

    'class'=>'CButtonColumn',

    'template'=>'{billing}{payment}{paymenthistory} {image}{status} {view}{update}{delete}',

    'htmlOptions'=>array('width'=>'300px'),

    'buttons'=>array

    (

        'billing' => array

        (

            'label'=>'Billing',

           'imageUrl'=>Yii::app()->request->baseUrl.'/themes/shadow_dancer/images/small_icons/invoice.png',

            'url'=>'"../billing/admin/".$data->id',

         //    'options'=>array('target'=>'_blank'),

        

        ),

          'payment' => array

        (

            'label'=>'Payment',

           'imageUrl'=>Yii::app()->request->baseUrl.'/themes/shadow_dancer/images/small_icons/bag.png',

            'url'=>'"../receivableledger/admin/".$data->id',

         //    'options'=>array('target'=>'_blank'),

        

        ),

             'paymenthistory' => array

        (

            'label'=>'Billing & Payment History',

           'imageUrl'=>Yii::app()->request->baseUrl.'/themes/shadow_dancer/images/small_icons/historyp.png',

            'url'=>'"../vwmember/view/".$data->id',

         //    'options'=>array('target'=>'_blank'),

        

        ),   

          'image' => array

        (

            'label'=>'Picture',

           'imageUrl'=>Yii::app()->request->baseUrl.'/themes/shadow_dancer/images/small_icons/page_white_picture.png',

           'url'=>'"../memberpicture/update/".$data->id',

          //   'options'=>array('target'=>'_blank'),

        ),

        

          'status' => array

        (

            'label'=>'Status Lookup',

           'imageUrl'=>Yii::app()->request->baseUrl.'/themes/shadow_dancer/images/small_icons/page_white_star.png',

           'url'=>'"../memberstatus/admin/".$data->id',

           //  'options'=>array('target'=>'_blank'),

        ),

        

       

    ),

),

	),

)); ?>




Hi,

first thank your for this extension, it helped me alot.

One issue has this extension, the code part for getting the column values needs additional code for each column type.

Because there "was" no getter function for the columns.

Therefore it was impossible to export data from columns like TotalColumn or CalcColumn which uses interal protected values to store the "total" which could be displayed in the footer.

But thanks to my issue from April 2010 and add a new comment to it a few days ago this issue will be fixed in 1.1.14

So you don’t need the code for each Column type to get the data.

But use the new getter functions like

$colum->getDataCellContent($row);

the same also now available for header and footer.

Hello. Is this possible to export all dbtable columns? Because in my cgridview i’m displaying only 5 columns, but in dbtable i have 10 columns. I export data using this code in my view:




$this->widget('EExcelView', array(

     'dataProvider'=> $dataprovider,

     'title'=>'Title',

     'autoWidth'=>false,

     'columns'=>array(

                'col1',

                'col2',

                'col3',

                'col4',

                'col5',

));



Hi phreak,

I refactored your original code with a lot of major changes to improve the performance, support PHPExcel 1.7.8+ (they removed the PDF Renderer), and made it so that the extension could be used as a component. Just to give an idea on the performance increase, for an Excel5 document containing 72 columns and 611 rows, using your extension would take about 2 minutes and 20 seconds, while now it’s taking about 26 seconds. This is also with using Yii’s cache capabilities.

Anyway, there are a lot of significant changes that I wanted to share. Rather than create a new extension, and take away any credit from you, I wanted to send you my file and a description of changes for you to review. If you’re interested and have some time, please let me know. If you prefer that I just fork your project on Github and create a new extension, that’s fine as well. I just wanted to run it by you first.

Thanks.

Hi thanks for writing extension! I ran into an issue I have been trying to solve with no luck, so figured I would ask here. Is it possible to set $disablePaging to false but export all the pages. Example someone searches my table by gender and the grid view has 20k records I do not want to have a 20k line long grid but I would like to be able to export all of the pages. If I enable it and then export, it will only export the first page of records. I am very new to Yii and fairly new to php. Any help would be appreciated.

Thanks

Hey there. Unfortunataly I can not get this to work (I do not know if it is because of EExcelview or PHPExcel). Could someone offer help? I describe my problem here: Cry for help

Edit: Issue resolved!