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.
Related
need help here..
iam trying gridview from 2 table relation. i have succes retrieving the data from first table into gridview but become no filter. so far this is what iam doing
public function search($params)
{
$query = Smwp::find()
->joinWith('mfwpData');
// 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;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
'id_sm_wp' => $this->id_sm_wp,
'tgl_surat' => $this->tgl_surat,
'tgl_terima' => $this->tgl_terima,
'tgl_cetak' => $this->tgl_cetak,
'no_agenda' => $this->no_agenda,
'index_hal' => $this->index_hal,
'index_cetak' => $this->index_cetak,
]);
$query->andFilterWhere(['like', 'no_surat', $this->no_surat])
->andFilterWhere(['like', 'judul_hal', $this->judul_hal])
->andFilterWhere(['like', 'lokasi_scan', $this->lokasi_scan])
->andFilterWhere(['like', 'ket_dispo', $this->ket_dispo])
->andFilterWhere(['like', 'mfwpData.npwp', $this->id_mfwp])
;
return $dataProvider;
}
and here is rules function. iam inserting id_mfwp into safe part
public function rules()
{
return [
[['id', 'id_sm_wp', 'no_agenda', 'index_hal', 'index_cetak'],
'integer'],
[['tgl_surat', 'tgl_terima', 'tgl_cetak', 'no_surat', 'judul_hal',
'lokasi_scan', 'ket_dispo', 'íd_mfwp'], 'safe'],
];
}
and here is my relation in model
public function getMfwpData()
{
return $this->hasOne(Mfwp::className(), ['id' => 'id_sm_wp']);
}
public function getNamaUser()
{
return $this->hasOne(Mfwp::className(), ['id' => 'id_sm_wp'])-
>with(['pejabat']);
}
and here is code in my index :
['attribute'=>'id_mfwp',
'label'=>'NPWP',
'format'=>'raw',
'value'=>'mfwpData.npwp'],
['attribute'=>'id_mfwp',
'label'=>'Nama Wajib Pajak',
'format'=>'raw',
'value'=>'mfwpData.nama_wp'],
['attribute'=>'id_mfwp',
'label'=>'Nama AR',
'format'=>'raw',
'value'=>'namaUser.pejabat.nama'],
i am still cannot show filter in gridview..thank for helping
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 have this problem: I need to get data from database and filter them. but then I need to use custom php function to filter those filtered results using data from it.
Clasic search function in ActiveDataProvider
public function search($params) {
$query = Passenger::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
// I guess my function would go like here
Passenger::filterResultsEvenMore($dataProvider);
$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;
}
// grid filtering conditions
$query->andFilterWhere([
'passenger_id' => $this->passenger_id,
// ...
'version' => $this->version,
'status' => $this->status,
]);
return $dataProvider;
}
So my question is how to work with results of dataProvider because if I vardump the variable it looks like this and no actual data there.
yii\data\ActiveDataProvider Object
(
[query] => common\models\PassengerQuery Object
(
[sql] =>
[on] =>
[joinWith] =>
[select] =>
[selectOption] =>
[distinct] =>
[from] =>
[groupBy] =>
[join] =>
[having] =>
[union] =>
[params] => Array()
[_events:yii\base\Component:private] => Array()
[_behaviors:yii\base\Component:private] => Array()
[where] => Array
(
[status] => 1
)
[limit] =>
[offset] =>
[orderBy] =>
[indexBy] =>
[emulateExecution] =>
[modelClass] => common\models\Passenger
[with] =>
[asArray] =>
[multiple] =>
[primaryModel] =>
[link] =>
[via] =>
[inverseOf] =>
)
[key] =>
[db] =>
[id] =>
[_sort:yii\data\BaseDataProvider:private] =>
[_pagination:yii\data\BaseDataProvider:private] =>
[_keys:yii\data\BaseDataProvider:private] =>
[_models:yii\data\BaseDataProvider:private] =>
[_totalCount:yii\data\BaseDataProvider:private] =>
[_events:yii\base\Component:private] => Array()
[_behaviors:yii\base\Component:private] =>
)
UPDATE
I need to use function like this for each record:
if (myFunction(table_column_1, table_column_2)) {
result_is_ok_return_it
} else {
do_not_return_this_record
}
Why do you don't add your additional filters to query object used in DataProvider?
You can parse your conditions to $query->andFilterWhere(). If you need custom function for it just modify $dataProvider->query object inside function. After execute query in data provider you can only filter results by manually filter array of models stored in $dataProvider->models
To get result use models property or getModels()
For example,
$dataProvider->models;
OR
$dataProvider->getModels();
I think I came across a solution, (looks like it is working)
http://www.yiiframework.com/doc-2.0/yii-data-basedataprovider.html#setModels()-detail
After I do all my usual search stuff as described in question at beginning, I would do something like this using setModels() function
class PassengerSearch extends Passenger
public $status; // virtual attribute not present in database table
public function rules()
{
return [
// ... some other rules
[['status'], 'safe'],
];
}
// ...
$filtered_models = [];
$filter_models = false; // if you only want to filter if there is some value
foreach ($dataProvider->models as $model) {
// if ($model->status == 1) // example
if (!empty($this->status) && $model->status == $this->status) { // better approach, using virtual attribute $status
$filter_models = true;
$filtered_models[] = $model;
}
}
if ($filter_models)
$dataProvider->setModels($filtered_models);
return $dataProvider;
}
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.
Maybe i miss understand something about ActiveDataProvider, when i want to join table with ->joinWith('user_display')->all();
I've got error: The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.
public function search($params)
{
$query = FinanceSettingsCheckoutcounter::find()->joinWith('user_display')->all();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
return $dataProvider;
}
ActivedataProvider needs a query. In your case you send the result of the query (all())
$query = FinanceSettingsCheckoutcounter::find()->joinWith('user_display');