PHP export to excel using eexcelview - php

Hi I'm trying to get data in excel with eexcelview . I have added the code in controller
$query = " some query from 4 tables ";
$dataProvider=new CSqlDataProvider($query, array(
'sort'=>array('attributes'=>array(
'col1',
'col2',
'col3',
'col4',
'col5' ),),));
$this->widget('application.extensions.EExcelView', array(
'dataProvider'=> $dataprovider,
'title'=>'Title',
'autoWidth'=>false,
));
My understanding is when this action is called, it will directly ask me to save excel report. But instead I'm getting error The "dataProvider" property cannot be empty.,
C:\wamp\www\yii\framework\zii\widgets\CBaseListView.php(106)
100 * Initializes the view.
101 * This method will initialize required property values and instantiate {#link columns} objects.
102 */
103 public function init()
104 {
105 if($this->dataProvider===null)
106 throw new CException(Yii::t('zii','The "dataProvider" property cannot be empty.'));
Also, same $dataprovider in CGridView works fine.
What is wrong in my code ?

PHP variables are case sensitive. So you must change your code to
$this->widget('application.extensions.EExcelView', array(
'dataProvider'=> $dataProvider,
'title'=>'Title',
'autoWidth'=>false,
));

Related

yii2 Setting read-only property: yii\data\Pagination::limit

I am trying to set the limit on my active data provider in Yii2 in the pagination to 5 records. Accordingly to THIS documentation, the $limit property is available, but I am getting this error:
Setting read-only property: yii\data\Pagination::limit
And my code is this:
$dataProvider = new ActiveDataProvider([
'query' => Order::find()
->where(['user_id' => $user_id]),
'sort' =>[
'defaultOrder' => [
'id' => SORT_DESC
]
],
'pagination' => [
'pageSize' => 20,
'limit' => 5,
],
]);
And my question is this: Why does this happen? The pageSize works if I erase the limit everything goes smooth... On limit everything fails... How can I solve this?
L.E: I found the source method that throws this error, in case it helps:
/**
* Sets value of an object property.
*
* Do not call this method directly as it is a PHP magic method that
* will be implicitly called when executing `$object->property = $value;`.
* #param string $name the property name or the event name
* #param mixed $value the property value
* #throws UnknownPropertyException if the property is not defined
* #throws InvalidCallException if the property is read-only
* #see __get()
*/
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} elseif (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
} else {
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
}
according to this, it seams I am trying to: getLimit() not setLimit()... any ideas why?
Pagination doesn't have property $limit,
#property integer $limit The limit of the data. This may be used to set the LIMIT value for a SQL statement
That value set by propery $pageSize.
If you need to get last 5 news and this must be work with pager you need something like this:
$dataProvider = new ActiveDataProvider([
'query' => Order::find()
->where(['user_id' => $user_id]),
'sort' =>[
'defaultOrder' => [
'id' => SORT_DESC
]
],
'pagination' => [
'pageSize' => 5,
],
]);
Many properties in Yii are read-only. There are 2 simple ways to find out whether a property is read only or not.
Using canSetProperty()
if there is a method with set prefix, for example setLimit()
On the other hand, you must set limit on your query, not pagination.
Maybe ArrayDataProvider will be better suited.
$query = new Query;
$provider = new ArrayDataProvider([
'allModels' => $query->from('post')->limit(5)->all(),
'key' => 'id',
'sort' => [
'defaultOrder' => [
'id' => SORT_DESC
]
]
]);
According to the Yii Guid Concept of Properties
A property defined by a getter without a setter is read only. Trying to assign a value to such property will cause an InvalidCallException. Similarly, a property defined by a setter without a getter is write only, and trying to read such property will also cause an exception. It is not common to have write-only properties.
There are several special rules for, and limitations on, the properties defined via getters and setters:
The names of such properties are case-insensitive. For example, $object->label and $object->Label are the same. This is because method names in PHP are case-insensitive.
If the name of such property is the same as a class member variable, the latter will take precedence. For example, if the above Foo class has a member variable label, then the assignment $object->label = 'abc' will affect the member variable 'label'; that line would not call the setLabel() setter method.
These properties do not support visibility. It makes no difference for the visibility of a property if the defining getter or setter method is public, protected or private.
The properties can only be defined by non-static getters and/or setters. Static methods will not be treated in the same manner.
So in other terms, there is no way do do this only with PHP. As it is said in the documentation, a thing that I just saw:
$limit public read-only property
integer getLimit( )
The limit of the data. This may be used to set the LIMIT value for a SQL statement for fetching the current page of data. Note that if the page size is infinite, a value -1 will be returned.
In order for this to work as expected, the code needs to become this:
$dataProvider = new ActiveDataProvider([
'query' => Order::find()
->where(['user_id' => $user_id])
->limit(5),
'sort' =>[
'defaultOrder' => [
'id' => SORT_DESC
]
],
'pagination' => false,
]);
Hope this helps others in my shoes!

Accessing value of indirectly related models

I am displaying a CGridView below CDetailView on view.php page for Company model. I have problem in displaying values in CGridView using company details. The company model has an array of CompanyAddresses which is used as CArrayDataProvider for CGridView.
$config = array();
$dataProvider = new CArrayDataProvider($rawData=$model->companyAddresses,$config);
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider
, 'columns'=>array(
//'id',
array('header'=>'SN.',
//'value'=>'++$row', // may nt work with pagination but the below does work
'value'=>'$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
'address',
array(
'name'=>'Tehsil',
//'value'=> Utility::getTehsilName(Tehsil::model()->findByPk('tehsil_id')),
'value'=> Utility::getTehsilName($this->loadModel('tehsil_id')),
//'value'=> Tehsil::model()->findByAttributes( array('id' => 'tehsil_id' ) )->name,
),
array(
'name'=>'address_tag_id',
'value'=>AddressTag::model()->findByPk('address_tag_id'),
),
)
));
I am not able to fetch Tehsil_Name from Tehsil Table which has its ID inside CompanyAddress table.
Your using value attribute is wrong, check this:
'value'=>function($data){
return Utility::getTehsilName($data->tehsil_id);
},
value is a php expression that is evaluated to produce the contents of the gridview cell as below
'value' => 'Utility::getTehsilName($this->grid->controller->loadModel($data->tehsil_id))'
If you had used relation chaining to solve this your expression would have been simplified to say:
'value' => '$data->model1->tehsil->name'
where model1 is the middle relation.

Create filter for CGridView

I have a module, that have one Controller, one set of view, and 5 models(in future can be more).
So in controller i have action
$model = new $modelName('search');
$model->unsetAttributes();
$model->create_user_id = Yii::app()->user->id;
if (isset($_GET[$modelName]))
$model->attributes = $_GET[$modelName];
$this->render('model_view/adminModel', array(
'modelName' => $modelName,
'model' => $model,
));
and in view i have a widget based on CGridView
$this->widget('application.components.widgets.usertheme.UserGridView',
array(
'id'=>'user-grid',
'dataProvider' =>$model->search(),
'filter'=>$model,
'columns' => .....
.....
)
);
If i put in action action (line #3)
$model->create_user_id = Yii::app()->user->id;
it works fine, and show the data that are created by user that is on system now.
But if i want to find inforamtion from this table, but with the filter - created document by USER from another table (i have relation with it)
'document' => array(self::BELONGS_TO, 'Document', 'document_id'),
and in action write
$model->document->create_user_id = Yii::app()->user->id;
it doesnt work, and give error
Indirect modification of overloaded property Reports::$document has no effect

How to convert model data objects array to dataProvider

Suppose I have model User which have many to many relation to itself named as friends.
so $user->friends (or $model->friends in view) gives me an array of User objects. I wanted to display the friends as gridview. But CGridView data as dataProvider object. Googling for it found the way to convert array of model objects to dataProvider object as given below.
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'gridUser',
'dataProvider' => new CArrayDataProvider($model->friends, array()),
));
Now using this I get an error
Property "User.id" is not defined.
UPDATE
public function relations()
{
return array(
'friends' => array(self::MANY_MANY, 'User', 'friendship(user_id, friend_id)'),
);
}
I use two stage building the provider shown below. But I found that it gives you trouble in terms of Pagination. I have not bothered to resolve that problem since am doing other things
$dataProvider = new CArrayDataProvider('User');
$dataProvider->setData($model->friends);
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'gridUser',
'dataProvider' =>$dataProvider,
));
That being said, your code should work (see the example below from API docs). I suspect there is wrong attribute in your relations than the provided code. Re-check the relation definition if it is ok
From Yii docs:
$rawData=Yii::app()->db->createCommand('SELECT * FROM tbl_user')->queryAll();
// or using: $rawData=User::model()->findAll(); <--this better represents your question
$dataProvider=new CArrayDataProvider($rawData, array(
'id'=>'user',
'sort'=>array(
'attributes'=>array(
'id', 'username', 'email',
),
),
'pagination'=>array(
'pageSize'=>10,
),
));
Got it :) , i can use CActiveDataProvider instead of CArrayDataProvider as given below
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'gridUser',
'dataProvider' => new CActiveDataProvider('User', array(
'data'=>$model->friends,
)),
//...... columns display list.....
));
Anyways thanks for the reply #Stefano

Yii - CGridView - add own attribute

$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
'title', // display the 'title' attribute
'category.name', // display the 'name' attribute of the 'category' relation
'content:html', // display the 'content' attribute as purified HTML
array( // display 'create_time' using an expression
'name'=>'create_time',
'value'=>'date("M j, Y", $data->create_time)',
),
array( // display 'author.username' using an expression
'name'=>'authorName',
'value'=>'$data->author->username',
//HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'htmlOptions'=>array('class'=>'$data->author->username', 'secondAttribute' => $data->author->id),
//HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
),
array( // display a column with "view", "update" and "delete" buttons
'class'=>'CButtonColumn',
),
),
));
In option value i can add variable from PHP, but for option htmlOptions this is not possible. Why?How can i make attribute with PHP variable?
When you add arrays in the columns collection without specifying a class property, the type of column being created is CDataColumn. The property CDataColumn::value is explicitly documented to be
a PHP expression that will be evaluated for every data cell and whose
result will be rendered as the content of the data cells.
Therefore, value has the special property that it gets eval'ed for each row and that's why you can set it "dynamically". This is an exception however, and almost nothing else supports the same functionality.
However, you are in luck because the property cssClassExpression is another special exception that covers exactly this usage case. So you can do it like this:
array(
'name'=>'authorName',
'value'=>'$data->author->username',
'cssClassExpression' => '$data->author->username',
),
Edit: I made a mistake while copy/pasting from your example and did not notice that you were trying to do the same thing for additional attributes inside htmlOptions (I have now deleted the relevant part of the code).
If you need to add more options for dynamic values you have no choice but to subclass CDataColumn and override the renderDataCell method (stock implementation is here).
Don't know if this still applies or not (given that there is an accepted answer), but there is a slightly better solution in the form of "rowHtmlOptionsExpression". This specifies an expression that will be evaluated for every row. If the result of the eval() call is an array, it will be used as the htmlOptions for the <tr> tag. So you can basically now use something like this:
$this->widget('zii.widgets.grid.CGridView', array
(
...
'rowHtmlOptionsExpression' => 'array("id" => $data->id)',
...
All your tags will have an id attribute with the records' PK.
Just modify the jQuery slightly to obtain the id from that tag instead of an extra column and you should be set.
Extend the class CDataColumn
Under protected/components/ create the file DataColumn.php with the following content:
/**
* DataColumn class file.
* Extends {#link CDataColumn}
*/
class DataColumn extends CDataColumn
{
/**
* #var boolean whether the htmlOptions values should be evaluated.
*/
public $evaluateHtmlOptions = false;
/**
* Renders a data cell.
* #param integer $row the row number (zero-based)
* Overrides the method 'renderDataCell()' of the abstract class CGridColumn
*/
public function renderDataCell($row)
{
$data=$this->grid->dataProvider->data[$row];
if($this->evaluateHtmlOptions) {
foreach($this->htmlOptions as $key=>$value) {
$options[$key] = $this->evaluateExpression($value,array('row'=>$row,'data'=>$data));
}
}
else $options=$this->htmlOptions;
if($this->cssClassExpression!==null)
{
$class=$this->evaluateExpression($this->cssClassExpression,array('row'=>$row,'data'=>$data));
if(isset($options['class']))
$options['class'].=' '.$class;
else
$options['class']=$class;
}
echo CHtml::openTag('td',$options);
$this->renderDataCellContent($row,$data);
echo '</td>';
}
}
We can use this new class like this:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'article-grid',
'dataProvider' => $model->search(),
'filter' => $model,
'columns' => array(
'id',
'title',
array(
'name' => 'author',
'value' => '$data->author->username'
),
array(
'class' => 'DataColumn',
'name' => 'sortOrder',
'evaluateHtmlOptions' => true,
'htmlOptions' => array('id' => '"ordering_{$data->id}"'),
),
array(
'class' => 'CButtonColumn',
),
),
));

Categories