I am getting my dataProvider from which I try to remove some models that don't meet the wanted criteria. This filter is not SQL related and therefore I can't apply it directly to the query. On my view the pagination links are displayed if I leave the dataprovider just as it was. But after I apply the filters to remove the unwanted models, the pagination links disappear. I have tried setting the pagination on my new dataProvider but nothing works.
Here's my code in the controller action:
$request = Yii::$app->request;
$search_model = new StaffEmploymentListViewSearch();
$data_provider = $search_model->search($request->queryParams);
$models = $data_provider->models;
for($k=0;$k<count($models);$k++)
{
if($models[$k]->employ === null){
unset($models[$k]);
}
}
$config = [
'pageParam' => 'page',
'pageSizeParam' => 'per-page',
'forcePageParam' => true,
'route' => null,
'params' => null,
'urlManager' => null,
'validatePage' => true,
'totalCount' => 5214,
'defaultPageSize' => 20,
'pageSizeLimit' => [
'0' => 1,
'1' => 50
],
'pagesize' => 20
];
$data_provider->setModels($models);
$data_provider->setPagination($config);
return $this->render('all-staff',[
'dataProvider' => $data_provider,
'searchModel' => $search_model
]);
Here's my search method:
$query = StaffEmploymentListView::find()
->SELECT([
'PAYROLL_NO',
'BIRTH_DATE',
"ADD_MONTHS(BIRTH_DATE, 70 * 12) AS RETIRE_DATE"
]);
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => false,
'pagination' => [
'pagesize' => 20,
],
]);
How do I go about doing this?
Try to use ArrayDataProvider
$query = StaffEmploymentListView::find()
->select([
'PAYROLL_NO',
'BIRTH_DATE',
"ADD_MONTHS(BIRTH_DATE, 70 * 12) AS RETIRE_DATE"
]);
$allModels = [];
foreach ($query->all as $staffEmployment)
{
if ($model->employ === null){
$allModels[] = $model;
}
}
$dataProvider = new ArrayDataProvider([
'allModels' => $allModels,
'pagination' => [
'pageSize' => 20,
],
'sort' => false
]);
return $this->render('all-staff',[
'dataProvider' => $data_provider,
'searchModel' => $search_model // ???
]);
Related
i have a search model where i need to get only active models (status 1) without deleted models (status 0) but it is showing all models including deleted ones
use yii\data\ActiveDataProvider;
public function search($params)
$query = Post::find()->where(['status' => 1]);
$provider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
'title' => SORT_ASC,
]
],
]);
// returns an array of Post objects
$posts = $provider->getModels();
This code do not execute the first condition where(['status' => 1])
why?
I was trying to make a search model for a mini Geo location system. Whenever I tried to get the data sorted by directly calling the GeoData model it works unless we try to sort.
But when we try to use the CustomMade SearchModel it sends :
Invalid argument supplied for foreach()
Here is the SearchModel:
<?php namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\GeoData;
/**
* This is the ActiveQuery class for [[GeoData]].
*
* #see GeoData
*/
class GeoDataSearch extends GeoData
{
const TODOS = 1;
const FECHA = 2;
const ENVIADO_POR = 3;
public function rules()
{
return [
[['latitude', 'longitude'], 'required'],
[['latitude', 'longitude', 'accuracy', 'speed', 'betterlocation'], 'number'],
[['device_id', 'active', 'sended', 'mobildate', 'created_at', 'updated_at', 'created_by'], 'integer'],
[['created_by'], 'exist', 'skipOnError' => true, 'targetClass' => User::class, 'targetAttribute' => ['created_by' => 'id']],
];
}
/*public function active()
{
return $this->andWhere('[[status]]=1');
}*/
public function scenarios()
{
return Model::scenarios();
}
public function search($params)
{
$query = GeoData::find()->where(['created_by' => $params])->all();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
]
]
]);
$dataProvider->sort->attributes['created_at'] = [
'asc' => ['created_at' => SORT_ASC],
'desc' => ['created_at' => SORT_DESC]
];
$dataProvider->sort->attributes['created_by'] = [
'asc' => ['created_by' => SORT_ASC],
'desc' => ['created_by' => SORT_DESC]
];
$dataProvider->sort->attributes['geo_id'] = [
'asc' => ['geo_id' => SORT_ASC],
'desc' => ['geo_id' => SORT_DESC]
];
$this->load($params);
$query->andFilterWhere([
'geo_id' => $this->geo_id,
'latitude' => $this->latitude,
'longitude' => $this->longitude,
'accuracy' => $this->accuracy,
'speed' => $this->speed,
'device_id' => $this->device_id,
'betterlocation' => $this->betterlocation,
'active' => $this->active,
'mobiledate' => $this->mobildate,
'sended' => $this->sended,
'updated_at' => $this->updated_at,
'created_at' => $this->created_at,
'created_by' => $this->created_by,
]);
return $dataProvider;
}
}
And the controller (The code that is commented works but it won't allow me to use the GridView nor filter or Sort:
public function actionView($id)
{
$title = "Ver Historial";
$id = $_GET['id'];
$searchModel = new GeoDataSearch;
$dataProvider = $searchModel->search($id);
return $this->render(
'view',
[
'title' => $title,
'searchModel' => $searchModel,
'dataProvider' => $dataProvider
]);
/*
if (Yii::$app->user->can(AuthItem::ROLE_ADMINISTRATOR))
{
$id = $_GET['id'];
$title = "Ver Historial";
$model = new GeoData;
$dataProvider = $model::findAll(['created_by'=> $id]);
return $this->render(
'view',
[
'title' => $title,
'dataProvider' => $dataProvider,
]
);
} else {
throw new ForbiddenHttpException('Access denied for user '.Yii::$app->user->identity->id);
}
*/
}
Any Suggestion will be really appreciated!
First your GeoDataSearch search() function should look like this:
public function search($params)
{
$query = GeoData::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [
'defaultOrder' => [
'created_at' => SORT_DESC,
]
]
]);
$this->load($params);
if (!$this->validate())
return $dataProvider;
$query->andFilterWhere([
'geo_id' => $this->geo_id,
'latitude' => $this->latitude,
'longitude' => $this->longitude,
'accuracy' => $this->accuracy,
'speed' => $this->speed,
'device_id' => $this->device_id,
'betterlocation' => $this->betterlocation,
'active' => $this->active,
'mobiledate' => $this->mobildate,
'sended' => $this->sended,
'updated_at' => $this->updated_at,
'created_at' => $this->created_at,
'created_by' => $this->created_by,
]);
return $dataProvider;
}
Add a second function to GeoDataSearch model:
/**
* #param int $creator_id ID of the creator
* #param mixed $params
* #return ActiveDataProvider
*/
public function searchByCreator($creator_id, $params)
{
// This will verify if the $params['GeoDataSearch'] index exists
if ( isset( $params['GeoDataSearch'] ) ) {
$params['GeoDataSearch']['created_by'] = $creator_id;
} else {
// Create the index if it doesn't exist
$params['GeoDataSearch'] = ['created_by' => $creator_id];
}
return $this->search($params);
}
Update your actionView:
public function actionView($id)
{
$title = "Ver Historial";
$searchModel = new GeoDataSearch;
// The $id param is already receiving the $_GET['id']
$dataProvider = $searchModel->searchByCreator($id, Yii::$app->request->queryParams);
return $this->render(
'view',
[
'title' => $title,
'searchModel' => $searchModel,
'dataProvider' => $dataProvider
]);
}
Don't setup user validation in the actionView, use AccessControl instead.
Explaining
DataProvider are for easy data pagination and sorting (View docs).
Querys filters the data for the DataProvider manipulation.
The search method is a convention for attaching query filters to a DataProvider in a single place for better reuse. So you should be looking to have a generic search method that can be reused on multiple scenarios.
In this example, the GeoDataSearch->search() method is used for searching multiple GeoData models by passing any parameter you want, so you will pass an array to it, most likely with the data from front-end.
If you are using Yii2 ActiveForm inputs (with GET method set) in your front-end, on GeoDataSearch fields. For example:
<?= $form->field($searchModel, 'speed')->textInput(); ?>
This will allow to filter the results by the speed attribute. When a user submit this form, your back-end will get the following content from Yii::$app->request->queryParams:
[
'GeoDataSearch' => [
'speed' => '10.00'
]
]
You should use this on the search method, that will filter all GeoData by their speed.
Important to notice that the speed attribute will be a index on GeoDataSearch. This is the way Yii2 builds params with their core form methods and affects the models load() method, and the reason that the implementation on searchByCreator seems a little convoluted.
Back to your case,
You need to filter by the creator. Since this needs to always be attached to the search query params, I recommend you to create a new method (searchByCreator), which consumes the already existing search method, force the created_by attribute, all while keeping the other filters alive.
I'm really new in Yii2 and I still don't know how to configure it properly. I noticed that the GridView has search fields on each column. What I need now is to create a main/single search field wherein a user can input keywords then results will show in the GridView after hitting the search button.
Is this possible? I also used this Kartik widget in my search form field which has a dropdown list in it. Image here.
We're told to use this dropdown search and when the user inputs some keywords (sometimes returns 'No results found' on the dropdown list), and clicks the Search button, the page will refresh displaying all the results based on the keywords inputted.
I also searched some problems same as mine here in SO, such as these:
Yii2 Search model without using GridView
yii 2 , make an active form text field master search field
I found no luck. The second link doesn't have any answers.
I will include my action controller here in case you need it.
public function actionIndex()
{
$session = Yii::$app->session;
$searchModel = new PayslipTemplateSearch();
$PayslipEmailConfig = PayslipEmailConfig::find()->where(['company_id'=> new \MongoId($session['company_id'])])->one();
$payslipTemplateA = PayslipTemplate::find()->where(['company_id' => new \MongoId($session['company_id'])])->andwhere(['template_name' => 'A'])->one();
$payslipTemplateB = PayslipTemplate::find()->where(['company_id' => new \MongoId($session['company_id'])])->andwhere(['template_name' => 'B'])->one();
$pTemplateModel = PayslipTemplate::find()->where(['company_id' => new \MongoId($session['company_id'])])->all();
$user = User::find()->where(['_id' => new \MongoId($session['user_id'])])->one();
$module_access = explode(',', $user->module_access);
$dataProvider = User::find()->where(['user_type' => 'BizStaff'])->andwhere(['parent' => new \MongoId($session['company_owner'])])->all();
return $this->render('index', [
'PayslipEmailConfig' => $PayslipEmailConfig,
'dataProvider' => $dataProvider,
'payslipTemplateA' => $payslipTemplateA,
'payslipTemplateB' => $payslipTemplateB,
]);
}
My view, index.php
<?php
$users = User::find()->where(['user_type' => 'BizStaff'])->andwhere(['parent' => new \MongoId($session['company_owner'])])->all();
echo $this->render('_search', ['model' => new User(), 'users' => $users]);
?>
_search.php
<?php $form = ActiveForm::begin([
'action' => ['searchresults'],
'method' => 'get',
'id' => 'searchForm'
]); ?>
<?php
$listData = array();
foreach ($users as $user) {
$listData[(string)$user->_id] = $user->employeeId. ' '.$user->fname.' '.$user->lname;
}
echo $form->field($model, '_id')->widget(Select2::classname(), [
'data' => $listData,
'addon' => [
'append' => [
'content' => Html::button('Search', ['class'=>'btn btn-primary']),
'asButton' => true
]
],
'options' => [ 'class' => 'dropdown-responsive', 'responsive' => true, 'placeholder' => 'Search employee ID or name (e.g. 10015 or John Cruz)', 'id' => 'user_id', 'name' => 'id'],
'pluginOptions' => [
'allowClear' => true,
'responsive' => true
],
]);
?>
<?php ActiveForm::end(); ?>
Really need help for this one.
This example code as per your requirement. so, try it.
User Searchmodel's search() method.
public function search($params)
{
$query = User::find();
$query->where(['user_type' => 'BizStaff'])->andwhere(['parent' => new \MongoId($session['company_owner'])])->all();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
......
........
}
Controller's actionIndex
public function actionIndex()
{
$session = Yii::$app->session;
/* $searchModel = new PayslipTemplateSearch(); */
$PayslipEmailConfig = PayslipEmailConfig::find()->where(['company_id'=> new \MongoId($session['company_id'])])->one();
$payslipTemplateA = PayslipTemplate::find()->where(['company_id' => new \MongoId($session['company_id'])])->andwhere(['template_name' => 'A'])->one();
$payslipTemplateB = PayslipTemplate::find()->where(['company_id' => new \MongoId($session['company_id'])])->andwhere(['template_name' => 'B'])->one();
$pTemplateModel = PayslipTemplate::find()->where(['company_id' => new \MongoId($session['company_id'])])->all();
$user = User::find()->where(['_id' => new \MongoId($session['user_id'])])->one();
$module_access = explode(',', $user->module_access);
$searchModel = new UserSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
/*
$dataProvider = User::find()->where(['user_type' => 'BizStaff'])->andwhere(['parent' => new \MongoId($session['company_owner'])])->all();
*/
return $this->render('index', [
'PayslipEmailConfig' => $PayslipEmailConfig,
'dataProvider' => $dataProvider,
'payslipTemplateA' => $payslipTemplateA,
'payslipTemplateB' => $payslipTemplateB,
'searchModel' => $searchModel,
]);
}
and index.php
<?php
$users = User::find()->where(['user_type' => 'BizStaff'])->andwhere(['parent' => new \MongoId($session['company_owner'])])->all();
echo $this->render('_search', ['model' => $searchModel, 'users' => $users]);
?>
I'm trying to display database for each user in descending date order using data provider this works for Yii 1 at controller :
$DataProvider = new CActiveDataProvider('ModelName', array(
'criteria' => array(
'condition' => 'user_id=' . Yii::app()->user->id,
'order' => 'submitted_dt DESC',
),
'pagination' => array(
'pageSize' => 20,
),
));
i try this in Yii 2 :
$DataProvider = new ActiveDataProvider([
'query' => ModelName::find(),
'criteria' => [
'condition' => 'user_id=' . Yii::$app->user->identity->id,
'order' => 'submitted_dt DESC',
],
'pagination' => [
'pageSize' => 20,
],
]);
// get posts in the current page
$Model= $DataProvider->getModels();
Error i get is unknown property: yii\data\ActiveDataProvider::criteria .So what is the way to set this condition and order ?
All suggestions are welcomed
The Yii2's right way would be:
$DataProvider = new ActiveDataProvider([
'query' => ModelName::find()->
where(['user_id'=>Yii::$app->user->identity->id])->
orderBy('submitted_dt DESC'),
'pagination' => [
'pageSize' => 20,
],
]);
// get posts in the current page
$Model= $DataProvider->getModels();
So, you don't need criteria in Yii2 as this is not exist anymore.
In Yii 1.1 this code works for default sorting:
$dataProvider = new CActiveDataProvider('article',array(
'sort'=>array(
'defaultOrder'=>'id DESC',
),
));
How default sorting can be set in Yii2?
Tried below code, but no result:
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => ['defaultOrder'=>'topic_order asc']
]);
I think there's proper solution. Configure the yii\data\Sort object:
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['topic_order' => SORT_ASC]],
]);
Official doc link
Or
$dataProvider->setSort([
'defaultOrder' => ['topic_order'=>SORT_DESC],
'attributes' => [...
defaultOrder contain a array where key is a column name and value is a SORT_DESC or SORT_ASC that's why below code not working.
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => ['defaultOrder'=>'topic_order asc']
]);
Correct Way
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [
'defaultOrder' => [
'topic_order' => SORT_ASC,
]
],
]);
Note: If a query already specifies the orderBy clause, the new ordering instructions given by end users (through the sort configuration) will be appended to the existing orderBy clause. Any existing limit and offset clauses will be overwritten by the pagination request from end users (through the pagination configuration).
You can detail learn from
Yii2 Guide of Data Provider
Sorting By passing Sort object in query
$sort = new Sort([
'attributes' => [
'age',
'name' => [
'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
'default' => SORT_DESC,
'label' => 'Name',
],
],
]);
$models = Article::find()
->where(['status' => 1])
->orderBy($sort->orders)
->all();
if you have CRUD (index) and you need set default sorting your controller for GridView, or ListView, or more...
Example
public function actionIndex()
{
$searchModel = new NewsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
// set default sorting
$dataProvider->sort->defaultOrder = ['id' => SORT_DESC];
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
you need add
$dataProvider->sort->defaultOrder = ['id' => SORT_DESC];
Try to this one
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$sort = $dataProvider->getSort();
$sort->defaultOrder = ['id' => SORT_ASC];
$dataProvider->setSort($sort);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['iUserId'=>SORT_ASC]]
]);
As stated in the guide, you must specify the sorting behaviors of a data provider by configuring its sort properties which correspond to the configurations for yii\data\Sort
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['topic_order' => SORT_ASC]],
]);
$modelProduct = new Product();
$shop_id = (int)Yii::$app->user->identity->shop_id;
$queryProduct = $modelProduct->find()
->where(['product.shop_id' => $shop_id]);
$dataProviderProduct = new ActiveDataProvider([
'query' => $queryProduct,
'pagination' => [ 'pageSize' => 10 ],
'sort'=> ['defaultOrder' => ['id'=>SORT_DESC]]
]);
you can modify search model like this
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [
'defaultOrder' => ['user_id ASC, document_id ASC']
]
]);