CActiveDataProvider with a regular non-database array - php

I have an array of $items in Yii application which I want to paginate. The array is not related to the database so there's no condition to consider here, just a bunch of defined items that I need to display. So I'm trying to use the CActiveDataProvider like this:
$dataProvider = new CActiveDataProvider($items, array(
'pagination' => array(
'PageSize' => 10,
)
));
$this->renderPartial('view', array('dataProvider'=>$dataProvider));
Then in the view I'm trying to display the information:
$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_view',
'template'=>"{items}\n{pager}",
));
I get a Call to a member function getDbCriteria() on a non-object fatal error which is totally understandable since my $items array is customized and not database related so my question is how can I go around this issue and is it even possible using the CActiveDataProvider?
If it's not, is there another way to create a pagination for a custom non-database related array?

There is CArrayDataProvider for this case.
$dataProvider=new CArrayDataProvider($items, array(
'pagination'=>array(
'pageSize'=>10,
),
));

Related

Join tables in Yii

I have a query like this:
SELECT jo . * , pc.checklist_id FROM job_order_candidates jo,
pdpa_checklist pc WHERE jo.job_id = '5755' AND jo.shortlisted = '1'
AND pc.job_id = '5755'
I need to write it in Yii format, how to do it? At the moment I have this code:
$dataProviderSL=new CActiveDataProvider('JobApplication', array(
'criteria'=>array(
'condition'=>'shortlisted='.JobApplication::SL_Y.' AND job_id='.$jobOrder->job_id,
'order'=>'applied_date DESC',
'with'=>array('candidate'),
),
'pagination'=>array(
'pageSize'=>20,
),
));
It's only select single table, I need to select 2 tables. Can anyone help me?
Thanks alot.
It's hard to find the correspondance bewteen your ActiveRecords and your table but you should try something like:
$dataProviderSL=new CActiveDataProvider('JobApplication', array(
'criteria'=>array(
'condition'=>'shortlisted= :shortlisted',
'order'=>'applied_date DESC',
'params' => array(
':shortlisted' => JobApplication::SL_Y,
':job_id' => $jobOrder->job_id,
),
'with'=>array('candidate' => array(
'together' => true,
'condition' => 'job_id= :job_id'
)),
),
pagination'=>array(
'pageSize'=>20,
),
));
I'm note sure if job_id is in the relation or the main model, if you want a more precise answer you have to provide us more infos.
That SQL does not make sense if you are to use CActiveDataProvider philosophy.
CActiveDataProvider would provide you with an array of JobApplication models, which should be stored on the rows of your job_order_candidates table. Since pc.checklist_id belongs to another table, you should have another model that represents those entries, and on your JobApplication class you need a relation with that model. Assuming it would be called PdpaChecklist, your JobApplication would look like this:
class JobApplication extends CActiveRecord {
// your stuff
public function relations() {
return array(
'pdpaChecklist' => array(self::HAS_ONE, 'PdpaChecklist', 'job_id'),
);
}
}
That given, you can query JobApplications as you currently do and access that pc.checklist_id like the following:
foreach ($dataProviderSl->getData() as $jobApplication) {
$jobApplication->pdpaChecklist->checklist_id;
}
Since you will be iterating through JobApplications, it is a good idea to use eager loading, preventing Yii to run a query everytime you do $jobApplication->pdpaChecklist. To do so, include 'pdpaChecklist' to your 'with' statement.
'with'=>array('candidate', 'pdpaChecklist'),
That is probably more work than you would have imagined, but that is how Yii organizes things. When you synergizes with the phylosophy it goes mych easily and faster. Totally worth it.

Maximum amount of items in one Page of Yii

I am developing this yii application and in the index i am displaying a "preview" of these items and currently it is display 8 items then it will pageinate itself. I would like make it page every 4 items and i have searched online and found that i could use the CPagination. I have followed the example in the documentation http://www.yiiframework.com/doc/api/1.1/CPagination and it is working but i don't know how to display the model i have the following code in the index.
foreach($models as $model):
endforeach;
$this->widget('CLinkPager', array(
'pages' => $pages,
));
Also the data that i want to display is Title, Content, Image and id and can i use the _view since i have everying set from there regarding css.
Also by defult the yii application display the index with a CListView is there a way where i can set the item limit there instead of using CPagination
If you want to just display 4 items on the index page, edit the index action like this:
public function actionIndex()
{
$dataProvider=new CActiveDataProvider('{Model}',
array(
'criteria' => array(
'select' => 'title_field,content_field,image_field',
'limit' => {Limit},
)
));
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
This code will return {Limit} models from the database, if you want to sort them by any field you will need to add 'order' to the criteria array lik this:
'criteria' => array(
'select' => 'title_field,content_field,image_field',
'order' => 'download_id DESC',
'limit' => {Limit},
)
In your view, use foreach and render partial to render the _view.
foreach($models as $model):
$this->renderPartial('//{Model}/_view', $model);
endforeach;
Hope that helps.

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.

Cakephp model with several datasources

I have a model called Forwards this model uses a table from my Database. However it is required for some of the views connected to this model to use my costum datasource (This is a datasource i have created which links it to an API).
Now my question how can i add a datasource to a Model that already has a datasource.
And how can i tell the Paginator that it has to use this datasource when it is paginating (so it doesnt confilct)
Update
I have been reading abit it seems the only way to use two datasource in a model is to Hack abit, so i was wondering is it possible to use two models from one controller while still paginating?
i want to keep these settings
public $paginate = array(
'fields' => array(
'Offer.id',
'Offer.name',
'OfferUrl.preview_url',
'Stat.ltr',
'Stat.cpc',
'Category.name',
'Country.name')
, 'conditions' => array('Stat.date' => array(
'conditional' => 'BETWEEN'
, 'values' => array()
),
),
'group' => array('Stat.offer_id'),
'Method' => 'getStats',
'totals' => true,
'limit' => 20
);
I set these within my controller
You can change the data source by calling Model::setDatasSource().
You can change the model the paginator uses by:
$this->Paginator->paginate($ModelInstance);
Or
$this->Paginator->paginate('ModelName');
You might want to read that page.
Don't use Controller::paginate any more but instead $this->Paginator->settings. For settings per model use
$this->Paginator->settings['ModelName'] = array(/*...*/);

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

Categories