I am using following code and the limit doesnt work. But if I see the command than it shows limit in that, but when I pass the query to ActiveDataProvider it fetch all the records:
$data= User::find()->where(['category_id'=> 5])->orderBy(['rand()' => SORT_DESC])->limit(4);
$command = $data->createCommand();
$data2 = $command->queryAll();// This works fine and fetch only 4 data
$dataProvider = new ActiveDataProvider([
'query' => $data,
]); // But this displays all data without limit
What is wrong I am doing here?
Here is what happens when preparing models in yii\data\ActiveDataProvider:
/**
* #inheritdoc
*/
protected function prepareModels()
{
if (!$this->query instanceof QueryInterface) {
throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.');
}
$query = clone $this->query;
if (($pagination = $this->getPagination()) !== false) {
$pagination->totalCount = $this->getTotalCount();
$query->limit($pagination->getLimit())->offset($pagination->getOffset());
}
if (($sort = $this->getSort()) !== false) {
$query->addOrderBy($sort->getOrders());
}
return $query->all($this->db);
}
We're interested in this part:
if (($pagination = $this->getPagination()) !== false) {
$pagination->totalCount = $this->getTotalCount();
$query->limit($pagination->getLimit())->offset($pagination->getOffset());
}
So as you can see if pagination is not false, limit is managed automatically.
You can just set pagination to false and then manual setting of limit will work:
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
]);
You can use Limit in the ActiveDataProvider and keep Pagination like so:-
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 50,
],
]);
$dataProvider->setTotalCount(1000);
This will make $this->getTotalCount() = 1000 and Keep the pagination.
Go here and here for more reference.
Related
Good afternoon, help me figure it out, using the OmgDef/yii2-multilingual-behavior extension, swears at this line:
public function actionIndex()
{
$data = new ActiveDataProvider([
'query' => FaqLang::find()->multilingual()->sort(), //error here
]);
return $this->render('index', [
'data' => $data
]);
}
My overridden model that stores the sort() method
<?
namespace admin\base;
/**
* Base active query class for models
* #package admin\base
*/
class ActiveQuery extends \yii\db\ActiveQuery
{
/**
* Order by order_num
* #return $this
*/
public function sort()
{
$this->orderBy(['order_num' => SORT_ASC]);
return $this;
}
}
You could try using the sort property of the ActiveDataProvider.
$data = new ActiveDataProvider([
'query' => FaqLang::find()
->multilingual()
->select(['id','question','answer']),
'sort' => [
'defaultOrder' => ['order_num' => SORT_ASC],
],
]);
To select columns use the select() method of the ActiveQuery object.
If you are using GridView to display results, you can also use it's columns property.
I am trying to use or operator in my rest request Yii2 but I cannot succeed.
Everytime I have this error :
[
{
"field": "filter",
"message": "Operator \"or\" requires multiple operands."
}
]
I tested several things but nothing works.
I want to filter
statut=0 or statut=1
Do you know or I can do it ?
I tried to
http://url/api/tickets/gestions?filter[or][statut][statut]=[0,1]
But it does not work
Here's the method within controller that manage this request :
public function actionIndex()
{
return ActionsHelper::actionIndex(
$this->modelClass,
$this->modelClass . 'Search'
);
}
$this->modelClass is defined above and is equal to 'api\modules\tickets\models\TicketGestion';
Here is ActionsHelper::actionIndex
public function actionIndex($model, $searchModel = null, $moreFilter = null,
$pagination = false)
{
$filterCondition = null;
if ($searchModel) {
$filter = new ActiveDataFilter([
'searchModel' => $searchModel
]);
if ($filter->load(\Yii::$app->request->get())) {
$filterCondition = $filter->build();
if ($filterCondition === false) {
return $filter;
}
}
}
$query = $model::find();
if ($filterCondition !== null) {
$query->andWhere($filterCondition);
}
if ($moreFilter !== null) {
$query->andWhere($moreFilter);
}
if ($pagination !== false) {
$pagination = [
'pageSize' => 100
];
}
return new ActiveDataProvider([
'query' => $query,
'pagination' => $pagination
]);
}
Here's the search model, generated by Gii
<?php
namespace api\modules\tickets\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use api\modules\tickets\models\TicketGestion;
/**
* TicketGestionSearch represents the model behind the search form of `api\modules\tickets\models\TicketGestion`.
*/
class TicketGestionSearch extends TicketGestion
{
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['id', 'priorite', 'quicree', 'quirea', 'statut', 'recurrentid', 'typerea', 'client'], 'integer'],
[['dispatch', 'service', 'type', 'sujet', 'datecrea', 'dateecheance', 'daterea'], 'safe'],
[['duree'], 'number'],
];
}
/**
* {#inheritdoc}
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = TicketGestion::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
if ($this->dispatch == 'null') {
$this->dispatch = 1;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
'priorite' => $this->priorite,
'quicree' => $this->quicree,
'quirea' => $this->quirea,
'datecrea' => $this->datecrea,
'dateecheance' => $this->dateecheance,
'daterea' => $this->daterea,
'duree' => $this->duree,
'statut' => $this->statut,
'recurrentid' => $this->recurrentid,
'typerea' => $this->typerea,
'client' => $this->client,
]);
$query->andFilterWhere(['like', 'service', $this->service])
->andFilterWhere(['like', 'type', $this->type])
->andFilterWhere(['like', 'sujet', $this->sujet])
->andFilterWhere(['likes', 'dispatch', $this->dispatch]);
return $dataProvider;
}
}
You were on a right track, using ActiveDataFilter, but building arrays from get is done like this (example is from my controller):
http://localhost/ntb/web/index.php?r=assembly%2Findex&filter[or][0][status]=1004&filter[or][1][status]=1005&page=1&per-page=10
so for your example it should be like this:
http://url/api/tickets/gestions?filter[or][0][statut]=0&filter[or][1][statut]=1
This was the way to build a working 'or' filter for me.
I want to return different fields depends on scenario. How can I set it in dataProvider?
$query = User::find();
$activeData = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
]);
Fields in User model:
public function fields()
{
if ($this->scenario == 'statistics') {
return [
'id',
'email',
'count'
];
}
return [
'id',
'name'
];
}
What about using the $select property?
$query = User::find()->select(['id','email','count']);
$activeData = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
]);
Or even better, create an ActiveQuery class for them:
class UserQuery extends ActiveQuery
{
public function statistics()
{
return $this->select(['id','email','count']);
}
/* add as many filtering functions as you need here */
}
Then override the find() method in the User class to use it:
public static function find()
{
return new \app\models\UserQuery(get_called_class());
}
Then do:
$activeData = new ActiveDataProvider([
'query' => User::find()->statistics(),
'pagination' => [
'pageSize' => 10,
],
]);
Note: In default implementation of Yii2 RESTful API you can also select the required fields within url by doing: GET /users?fields=id,email,count
Simply get all the models using getModels() method, set scenario for all of them in the loop and then return data provider. Your example will change into following code:
$query = User::find();
$activeData = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
],
]);
foreach($activeData->getModels() as $model) {
$model->scenario = 'statistics';
}
return $activeData;
I have a Yii2 searchQuery setup which works very well for calculating those records not within the desired radius of a given point.
public function search($params)
{
$query = TrainerExtend::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => $this->pageSize,
],
]);
$this->load($params);
$query->having([
'<',
'ST_Distance_Sphere(POINT(' . $this->longitude . ',' . $this->latitude . '),
PointFromText(CONCAT(\'POINT(\',longitude,\'\',latitude,\')\')))',
$this->radius * 1000
]);
}
$rows = $query->distinct();
return $dataProvider;
}
public function actionFind()
{
$searchModel = new TrainerSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$trainers = $dataProvider->getModels();
if (array_key_exists('trainerSearch',Yii::$app->request->queryParams)
&& !empty($trainerSearch = Yii::$app->request->queryParams['TrainerSearch']))
{
if (array_key_exists('specialties',$trainerSearch) && !empty($specialities = $trainerSearch['specialties']))
{
foreach ($trainers as $trainer) {
$specialties = $trainer->trainerSpecialtiesArray;
$trainer->match = $this->caluclateRelevance($specialties);
}
}
}
return $this->render('find', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
resulting query
SELECT DISTINCT * FROM `trainer` WHERE `gender`='0' HAVING ST_Distance_Sphere(POINT(-123.3836214,48.418248899999995), PointFromText(CONCAT('POINT(',longitude,' ',latitude,')'))) < 59000 LIMIT 2`
Resulting record is bang on for radius calculations, however I need the distance calculated by the geo function as well. I have tried using an as keyword, but it keeps breaking the query.
For calculated column you must add the proper select code in you query
$query->->addSelect(["*",
"ST_Distance_Sphere(POINT($this->longitude ,
$this->latitude ),
PointFromText(CONCAT('POINT(',longitude,' ',latitude,')')))as distance"]);
then for show the result
first you should add a public var in you model eg:
class TrainerExtend extends \yii\db\ActiveRecord
{
public $distance; // codice di stato del codice fiscale
......
public static function tableName()
{
....
and second you can use distance as a model attribute in your views eg: gridview
<?= GridView::widget([
'dataProvider' => $dataProvider,
......
'columns' => [
.....
'distance',
...
I am writing some unit tests and struggling to capture the 1 remaining line of this small model in Yii2.
UserSearch.php
public function search($params)
{
$query = User::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// $query->where('0=1');
return $dataProvider; // This line in tests is red and marked as not executed
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
'date_added' => $this->date_added,
'last_login' => $this->last_login,
]);
$query->andFilterWhere(['like', 'username', $this->username])
return $dataProvider;
}
UserTest.php
public function testUserSearch()
{
$model = new UserSearch();
expect_that($model->search(['id' => 2]));
}
public function testInvalidDataProvider()
{
$model = new UserSearch();
expect_that($model->search(['id' => '2']));
}
The second test passes correctly as !this->Validate() method fails as id isn't an integer, why isn't the return statement reflected as executed in the code coverage. what am I misunderstanding here?
Integer must contain only digits [see validation]: https://github.com/yiisoft/yii2/blob/master/framework/validators/NumberValidator.php#L51 '2' is valid integer
model->search() return ActiveDataProvider. Is correct.