Please can someone explain how the search method in a Yii2 SearchModel works? I generated it using Gii. Here it is:
public function search($params){
$query = MyModel::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$this->addCondition($query, 'att1');
$this->addCondition($query, 'att1', true);
$this->addCondition($query, 'att2');
$this->addCondition($query, 'att2', true);
return $dataProvider;
}
This is how I call it:
$search = new MyModelSearch();
$myModels = $search->search(['att3' => '3']);
Regardless of what attributes I use in calling search, I always get back the same result - i.e. all the entries in the table. I'm missing something here that I just do not understand.
Any help would be really appreciated. Thanks.
The search() function generated by Gii use ActiveRecord::load() to set search parameters :
load() gets the 'FormName' from the model's formName() method (which you may override), unless the $formName parameter is given. If the form name is empty, load() populates the model with the whole of $data, instead of $data['FormName'].
So you should try :
$myModels = $search->search(['MyModelSearch'=>['att3'=>3]]);
Or
$myModels = $search->search([$search->formName()=>['att3'=>3]]);
And of course add a condition on att3 attribute in search() function :
$this->addCondition($query, 'att3');
But if you really want to use $myModels = $search->search(['att3' => '3']); then you should simply replace $this->load($params) with $this->load($params, '').
If you want some additional param to pass to search() method, you can change search method like this in SomeSearch.php:
public function search($params, $additional=0)
{
//...
if($additional==1) {
$query->andWhere(['status'=>['some', 'other']);
}
}
and inside controller:
public function actionIndex()
{
$searchModel = new AdminSearch();
$additional=1;
$dataProvider = $searchModel->search(Yii::$app->request->queryParams, $additional);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
$searchModel = new CursadoSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->query->andWhere([ 'cursado.curso_id' => $curso_id]);
Related
I want to display column from another table in gridview.
In my controller actionIndex:
public function actionIndex()
{
$user_id = \Yii::$app->user->identity->id;
$queryFile = PowerGen::find();
$queryFile ->select(['submitted_by','filename.file_name','filename.submitted_by'])
->joinWith('filename')//Tells Yii to use the complains relation that we define below. By default it is an inner join
->where(['filename.submitted_by' => $this->user_id]);
$dataProvider= new ActiveDataProvider([
'query' => $query,
'pagination' => false,
]);
return $this->render('index', ['dataProvider4'=>$dataProvider]);
}
In my model:
public function fileName()
{
$user_id = \Yii::$app->user->identity->id;
return $this->hasMany(Filename::className(), 'submitted_by' => $this->user_id);
}
Error is:
Error
PHP Parse Error – yii\base\ErrorException
syntax error, unexpected '=>' (T_DOUBLE_ARROW)
What is the error in the line..
Thank you
Use hasMany() like
public function fileName()
{
$user_id = \Yii::$app->user->identity->id;
return $this->hasMany(Filename::className(), ['submitted_by' => $this->user_id]);
}
First i think your function must be like this:
public function fileName()
{
return $this->hasMany(Filename::className(), ['submitted_by' => 'user_id']);
}
And your query like this:
$user_id = \Yii::$app->user->identity->id;
$queryFile = PowerGen::find();
$queryFile ->select(['submitted_by','filename.file_name','filename.submitted_by'])
->joinWith('filename')
->where(['filename.submitted_by' => $user_id]);
You are declaring the variable $user_id
$user_id = \Yii::$app->user->identity->id;
but you are not using it anywhere.
You're defining your relation in a wrong way:
Method name should be prefixed by get, like getFileName().
Second argument of hasMany() should be array with map of column names. You should not use dynamic values here or model attributes.
You should not use Yii::$app->user->identity->id or POST/GET data in your model. It breaks MVC pattern and will create problems if you will try to use this relation in console for example.
public function getFileName() {
return $this->hasMany(Filename::className(), ['submitted_by' => 'user_id']);
}
I have a yii2 form which contain a checkbox list items which i made like this:
<?php $CheckList = ["users" => 'Users', "attendance" => 'Attendance', "leave" => 'Leave', "payroll" => 'Payroll'];?>
<?= $form->field($model, 'MenuID')->checkboxList($CheckList,['separator'=>'<br/>']) ?>
Now what i need is to save the values in the database column as a comma separated value.
I tried to modify the create function in my controller in this way:
public function actionCreate()
{
$model = new Role();
if ($model->load(Yii::$app->request->post())) {
if ($model->MenuID != " ") {
$model->MenuID = implode(",", $model->MenuID);
}
$model->save();
return $this->redirect(['view', 'id' => $model->RoleID]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
But the values are not being saved in the database
You need to set your model rules().
When you call $model->load(Yii::$app->request->post()); the framework call method setAttributes() with param $safeOnly = true. This method with param $safe = true check if attributes are safe or not according to the rules of model. If you haven't any rules on the model all attributes are considered unsafe so your model is not populated.
Add rules() on your model and your code works
class Role extends yii\db\ActiveRecord
{
...
public function rules()
{
return [
['MenuID', 'your-validation-rule'],
];
}
...
Some additional info
N.B. If you do not specify scenario in the rules the default scenario is 'default' and if during instantiate of model object you set scenario to another didn't work. My example:
You have the same rules as I wrote before and you run this code
...
$model = new Role(['scenario' => 'insert']);
if ($model->load(Yii::$app->request->post())) {
...
model is empty after load becouse any rules is founded in 'insert' scenario and your problem is back. So if you want a rule that work only in particular scenario you must add 'on' rules definition. Like this:
...
public function rules()
{
return [
['MenuID', 'your-validation-rule', 'on' => 'insert'],
];
}
...
For more example and explanations visit:
Declaring Rules
load()
setAttributes()
safeAttributes()
Am using yii\rest\ActiveController without pagelimit
This is how am doing it
<?php
namespace rest\modules\v1\controllers;
use yii\rest\ActiveController;
class CompanyController extends ActiveController
{
public $modelClass = 'frontend\models\TblDeliveredCompanies';
}
The above returns only 20 records how do i improve it to return all
You can override prepareDataProvider() inside the controller to return a custom data provider from index action:
public function prepareDataProvider()
{
$query = \frontend\models\TblDeliveredCompanies::find();
$dataProvider = new \yii\data\ActiveDataProvider([
'query' => $query,
'pagination' => ['pageSize' => 0]
]);
return $dataProvider;
}
Check documentation at http://www.yiiframework.com/doc-2.0/guide-rest-controllers.html#extending-active-controller
The limit for 20 could be related to the default pagination values for dataProvider so in your controller/action or in the model where the $dataProvider is create you shoul redefine the function assign the pagination as false
$dataProvider->pagination = false;
or
$dataProvider = new ActiveDataProvider([
'query' => $your_query,
'pagination' => false,
]);
Check the code in the model class 'TblDeliveredCompanies' present at 'frontend\models\TblDeliveredCompanies' it must have the SQL query containing the limit 20, change it to 'SELECT * from yourtbl where %yourcond%'
Other solution
public function actions()
{
$actions = parent::actions();
$actions['index']['pagination'] = false;
return $actions;
}
I try to build a grid view with many-to-many relations. So I need a query for the ActiveDataProvider .
I have a table 'ressource', a table 'type' and between them a table 'historique'.
I have the good relation in my models but I don't know how to create the dataProvider.
In my model Ressource :
public function getHistorique()
{
return $this->hasMany(Historique::className(), ['idType' => 'idType']);
}
public function getType()
{
return $this->hasMany(Type::className(), ['idType' => 'idType'])
->viaTable(Historique::className(), ['idRessource' => 'idRessource']);
}
In my model Historique :
public function getType()
{
return $this->hasOne(Type::className(), ['idType' => 'idType']);
}
public function getRessource()
{
return $this->hasOne(Ressource::className(), ['idRessource' => 'idRessource']);
}
and finally in my model Type :
public function getHistorique()
{
return $this->hasMany(Historique::className(), ['idType' => 'idType']);
}
public function getRessource()
{
return $this->hasMany(Ressource::className(), ['idRessource' => 'idRessource'])
->viaTable(Historique::className(), ['idType' => 'idType']);
}
So in the Controller (in fact my ModelSearch), I want to have ressources with type from the table historique. I don't know what I have to add after
Ressource::find();
I think you use RessourceSearch()->search() method. So inside it you have something like this:
$query = Ressource::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
// Here is list of searchable fields of your model.
$query->andFilterWhere(['like', 'username', $this->username])
->andFilterWhere(['like', 'auth_key', $this->auth_key])
return $dataProvider;
So, basically, you need to add additional Where you your query and force to join relation table. You can do that using joinWith method to join additional relation and andFilterWhere using table.field notation for adding filter parameters. For example:
$query = Ressource::find();
$query->joinWith(['historique', 'type']);
$query->andFilterWhere(['like', 'type.type', $this->type]);
$query->andFilterWhere(['like', 'historique.historique_field', $this->historique_field]);
Also do not forget to add rules for additional filters in your search model. For example above, you should add to your rules() array something like that:
public function rules()
{
return [
// here add attributes rules from Ressource model
[['historique_field', 'type'], 'safe'],
];
}
You can use any additional validation rules for that fields
i'm new in YII and I want to set in my constructor something like
public function __construct(Car $car)
{
$this->car= $car;
}
and use my model to peform the query anything like
public function actionIndex()
{
$this->car->select('id','color')->all();
$this->render('index', array( 'car' => $car));
}
If you're using Yii than there is no need to inject $car in controller constructor.
public function actionIndex()
{
$cars = Car::find()->all();
return $this->render('index', [
'cars' => $cars
]);
}