How to implement single search form in yii2 - php

Yii2 has a searchModel to search each field in the GridView. Is it possible to just create a single search field outside the GridView where the user can input keywords and by the time Search button is hit, the results will display in the GridView based on the keywords entered.
CONTROLLER
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();
$searchModel = new UserSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'PayslipEmailConfig' => $PayslipEmailConfig,
'dataProvider' => $dataProvider,
'payslipTemplateA' => $payslipTemplateA,
'payslipTemplateB' => $payslipTemplateB,
'searchModel' => $searchModel,
]);
}
public function actionSearchresults($keyword)
{
$session = Yii::$app->session;
if ( $keyword == '') {
return $this->redirect(\Yii::$app->request->getReferrer());
} else {
$user = User::find()->where( [ '_id' => new \MongoId($id) ] )->one();
$searchModel = new PayslipTemplateSearch();
$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();
return $this->render('searchresults', [
'searchModel' => $searchModel,
'user' => $user,
'payslipTemplateA' => $payslipTemplateA,
'payslipTemplateB' => $payslipTemplateB,
]);
}
}
I asked a question connected to this problem here: Main Search Form in Yii2
It didn't due to some complications in Kartik's Select2 search dropdown widget. Now I switched temporarily to a simple Yii2 search field.
VIEW
echo $form->field($model, '_id')->textInput(array('placeholder' => 'search'))->label(false);
MODEL
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\User;
/**
* UserSearch represents the model behind the search form about `app\models\User`.
*/
class UserSearch extends User
{
/**
* #inheritdoc
*/
public function rules()
{
return [
[[/*'_id',*/ 'creator_id'], 'integer'],
[['fname', 'lname', 'email', 'username', 'user_type'], 'safe'],
];
}
/**
* #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)
{
$session = Yii::$app->session;
$query = User::find();
$query->where(['user_type' => 'BizStaff'])->andwhere(['parent' => new \MongoId($session['company_owner'])]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
$query->andFilterWhere([
'_id' => $this->_id,
'creator_id' => $this->creator_id,
]);
$query->andFilterWhere(['like', 'fname', $this->fname])
->andFilterWhere(['like', 'lname', $this->lname])
->andFilterWhere(['like', 'email', $this->email])
->andFilterWhere(['like', 'username', $this->username])
->andFilterWhere(['like', 'user_type', $this->user_type]);
return $dataProvider;
}
}
Do you have any idea on how to I implement a single search? It's kind of a smarter search since it can search everything in the database table based on keywords inputted.
EDIT
When I search a keyword, say for example 'hello', it then gives me this url and error after hitting enter key:
URL:
http://localhost/iaoy-dev/web/index.php?r=payslip-template%2Fsearchresults&PayslipTemplateSearch%5B_id%5D=hello
Error message:
Bad Request (#400) Missing required parameters: id
Help.

I had the same problem and my solution is:
Model
Extend your UserSearch Model with a search parameter
class UserSearch extends User
{
public $searchstring;
...
Enable passing the variable
public function rules()
{
return [
...
[['searchstring'], 'safe'],
];
}
Change your search-Method (beware: the searchfields are combined with orFilterWhere, depends on your needs).
$query->orFilterWhere(['like', 'fname', $this->searchstring])
->orFilterWhere(['like', 'lname', $this->searchstring])
->orFilterWhere(['like', 'email', $this->searchstring])
->orFilterWhere(['like', 'username', $this->searchstring])
->orFilterWhere(['like', 'user_type', $this->searchstring]);
View (could be also layout)
Extend your form with a search-input. You can style the input-field by yourself, this is just an example:
<?php
/* #var $searchModel app\models\UserSearch */
echo $form->field($searchModel, 'searchstring', [
'template' => '<div class="input-group">{input}<span class="input-group-btn">' .
Html::submitButton('GO', ['class' => 'btn btn-default']) .
'</span></div>',
])->textInput(['placeholder' => 'Search']);
?>
Controller
Also check for the value of $searchstring after posting the form.
public function actionIndex()
{
...
$searchModel = new UserSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
...
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
That's it.

Related

Yii2 Trying to get property of non-object error with listView relational model

I have two tables.
students(id,email,password,f_name,l_name,unique_id,create_date,last_update)
comments(id,ad_id,commented_user,comment,create_date,last_update)
table relation
-> comments.commented_user = students.email
comments class
class Comments extends \yii\db\ActiveRecord
{
//public $commented_user_fName;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'comments';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['comment'], 'string'],
[['create_date', 'last_update'], 'safe'],
[['ad_id', 'commented_user'], 'string', 'max' => 64],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'ad_id' => 'Ad ID',
'commented_user' => 'Commented User',
'comment' => 'Comment',
'create_date' => 'Create Date',
'last_update' => 'Last Update',
];
}
public function beforeSave($insert) {
if ($this->isNewRecord){
$this->commented_user = $_SESSION['login_student_email'];
$this->create_date = new Expression('NOW()');
}
return parent::beforeSave($insert);
}
public function getStudentName(){
$this->hasOne(Students::className() ,['commented_user' => 'email']);
}
}
My comment Controller Index methord
public function actionIndex($id)
{
$model = new Comments();
$model->setAttribute('ad_id',$id);
$searchModel = new CommentsSearch();
$dataProvider = $searchModel->search(["CommentsSearch"=>['ad_id'=>$id]]);
return $this->renderAjax('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'model' => $model,
]);
}
I try to get f_name of student table in my ListView
<?=
ListView::widget([
'dataProvider' => $dataProvider,
'layout' => "{items}",
'itemView' => 'view',
]);
?>
Item view file code below
<?= $model->studentName->f_name ?>
I got this error
PHP Notice – yii\base\ErrorException
Trying to get property of non-object
on this line <?= $model->studentName->f_name ?>
What is wrong with my code. Please help me
. is concatenation operator, so $model->studentName.f_name is not treated as $model->{studentName.f_name} but as {$model->studentName} . f_name.
You probably need to use $model->studentName->f_name.
You should access to the property as $model->studentName->f_name as with any other Model

Yii2 Gridview filtering a column that has Int data type based on varchar as inputed value

I've an gridView for showing data. GridView table has a column that called as Created By, this column contain the ID of User that I get from user table. Basicly, this column will show data as Integer(ID) like this:
But I've set code like this to show the username of the ID:
[
'attribute' => 'created_by',
'format' => 'raw',
'value' => function ($data) {
$modelUser = Users::find()->where(['id' => $data->created_by])->one();
$nama = $modelUser->username;
return $nama;
},
'vAlign' => 'middle',
'hAlign' => 'center',
],
Result:
The gridView has filter column, I'm trying to filter data based on inserted value. I'm trying input username as the value for filtering but it give an error message "created By must be an Integer", like this:
How do I can filtering that column using the a username(varchar)?
Thanks
Update
This is my searchModel.php
<?php
namespace app\search;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Product;
/**
* ProductSearch represents the model behind the search form of `app\models\Product`.
*/
class ProductSearch extends Product {
/**
* #inheritdoc
*/
public function rules() {
return [
[['productId', 'userId', 'parentId', 'created_by'], 'integer'],
[['date', 'created_at', 'name', 'address'], 'safe'],
[['price'], '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 = Product::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
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'productId' => $this->productId,
'price' => $this->price,
'created_at' => $this->created_at,
'created_by' => $this->created_by,
]);
$query->andFilterWhere(['MONTH(date)' => $this->date])
->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'address', $this->address]);
return $dataProvider;
}
}
public function rules()
{
return [
[['productId', 'userId', 'parentId'], 'integer'],
[['date', 'created_at', 'name', 'address'], 'safe'],
[['price'], 'number'],
[['created_by'], 'string'],
];
}
public function search($params)
{
$query = Product::find()->joinWith('createdBy'); // Whatever relation name
.
.
.
.
.
// grid filtering conditions
$query->andFilterWhere([
'productId' => $this->productId,
'price' => $this->price,
'created_at' => $this->created_at,
]);
$query->andFilterWhere(['MONTH(date)' => $this->date])
->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'address', $this->address])
->andFilterWhere(['like', 'userTableName.username', $this->created_by]); // Whatever table name and field name.
return $dataProvider;
}
You should add a proper filter to your column
[
'attribute'=>'your_attribute',
......
'filter'=>ArrayHelper::map(YourModel::find()->asArray()->all(),
'your_id_column', 'your_name_column'),
],

How to merge filters from one search model to one findModel from a controller in Yii 2?

The question is confusing, but I'll explain.
I have this search query from AsistenciaSearch.php
public function search($params)
{
$query = Asistencia::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;
}
$query->joinWith('rutAlumno0');
$query->joinWith('idPlanificacion0');
// grid filtering conditions
$query->andFilterWhere([
'idAsistencia' => $this->idAsistencia,
//'idPlanificacion' => $this->idPlanificacion,
]);
$query->andFilterWhere(['like', 'asistencia', $this->asistencia])
->andFilterWhere(['like', 'rutAlumno', $this->rutAlumno])
//->andFilterWhere(['like', 'idPlanificacion', $this->idPlanificacion])
->andFilterWhere(['like', 'alumno.nombreAlumno', $this->nombreAlumno])
->andFilterWhere(['like', 'alumno.apellidoAlumno', $this->apellidoAlumno])
->andFilterWhere(['like', 'alumno.cursoAlumno', $this->cursoAlumno])
->andFilterWhere(['like', 'alumno.establecimientoAlumno', Yii::$app->user->identity->escuelaProfesor]);
return $dataProvider;
}
And this a controller function using the search query in PlanificacionController.php:
public function actionVerasistencia($id)
{
$searchModel = new AsistenciaSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('verasistencia', [
'model' => $this->findModel($id), //findModel from Planificacion
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
Both Asistencia and Planificacion are related by using a primary key in Planificacion named idPlanificacion and a foreign key from that model in Asistencia using the same name.
The question is, I need to make merge with another filter, where the $id from findModel($id) is like the $idPlanificacion from the search query, like this:
public function actionVerasistencia($id)
{
$searchModel = new AsistenciaSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('verasistencia', [
'model' => $this->findModel($id),
'searchModel' => $searchModel,
'dataProvider' => $dataProvider->andFilterWhere('like',$id,$this->idPlanificacion),
]);
}
But I got this error:
Getting unknown property: frontend\controllers\PlanificacionController::idPlanificacion
Any solution, please?
$this inside the controller is related to the controller itself
but your are referring to idPlanificacion alias you are referring to a model attribute
could be you want retrive the value by the model eg:
$model = $this->findModel($id)
so could be
public function actionVerasistencia($id)
{
$searchModel = new AsistenciaSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$model = $this->findModel($id);
return $this->render('verasistencia', [
'model' =>$model,
'searchModel' => $searchModel,
'dataProvider' => $dataProvider->andFilterWhere('like',$id,$model->idPlanificacion),
]);
}

Yii2 filter Sum data in GridView

I'm trying display and filter data which I got via SQL SUM operator.
I have 2 table employee and department. Table employee contains department_id filed and salary filed. I need display all department and total SUM salary for every department.
I followed this guide, but GridView does not display any data.
Here is action:
public function actionIndex()
{
$searchModel = new DepartmentFrontendSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index',
[
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
]
);
}
Model:
class DepartmentFrontendSearch extends DepartmentFrontend
public $employee_count;
public $salary;
public function rules() {
return [
[['employee_count','salary','name'], 'safe']
];
}
public function search($params) {
$query = DepartmentFrontend::find();
$subQuery = Employee::find()
->select('department_id, SUM(salary) as salary_amount')
->groupBy('department_id');
$query->leftJoin(['salarySum' => $subQuery], 'salarySum.department_id = id');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->setSort([
'attributes' => [
'name',
'salary'
]
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
$query->andFilterWhere(['like', 'name', $this->name]);
$query->andWhere(['salarySum.salary_amount' => $this->salary]);
return $dataProvider;
}
GRID:
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'salary_amount',
'employee_count',
'name',
],
]);
So, can anybody tell me what I did wrong?
If You need a filter for the alias salary_amount you should add a specific var for this (do the fact salary_amount is an alias for sum(salary) the var $salary is not useful)
public $employee_count;
public $salary;
public $salary_amount;
otherwise use salary as alias too
the in your filter you are using
$query->andWhere(['salarySum.salary_amount' => $this->salary]);
But salary_amount is the result of an aggregation so you should use having(SUM(salary) = $this->salary_amount)
$query->having('SUM(salary) = ' . $this->salary_amount);

How to show relational data in yii2

I'm having trouble understanding how relations work in yii 2
I have 2 tables in a mysql database, author and book.
book has a column named author which links to the id of the author table via foreign key.
I've generated CRUD using gii, and I want the author name to appear in the list view, as well as dropdowns for the author name in the create and update views.
But I cant seem to get the relation working even in the list view.
Here's my code
Book Model:
<?php
namespace app\models;
use Yii;
use app\models\Author;
/**
* This is the model class for table "book".
*
* #property integer $id
* #property string $name
* #property integer $author
*/
class Book extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'book';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['name', 'author'], 'required'],
[['author'], 'integer'],
[['name'], 'string', 'max' => 11]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
'author' => 'Author',
];
}
public function getAuthor()
{
return $this->hasOne(Author::className(), ['id' => 'author']);
}
}
BookSearch Model:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Book;
/**
* BookSearch represents the model behind the search form about `app\models\Book`.
*/
class BookSearch extends Book
{
/**
* #inheritdoc
*/
public function rules()
{
return [
[['id', 'author'], 'integer'],
[['name'], 'safe'],
];
}
/**
* #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 = Book::find();
$query->joinWith('author');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
var_dump($dataProvider);
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;
}
$query->andFilterWhere([
'id' => $this->id,
'author' => $this->author,
]);
$query->andFilterWhere(['like', 'name', $this->name]);
return $dataProvider;
}
}
Also, here's the view file:
<?php
use yii\helpers\Html;
use yii\grid\GridView;
/* #var $this yii\web\View */
/* #var $searchModel app\models\BookSearch */
/* #var $dataProvider yii\data\ActiveDataProvider */
$this->title = 'Books';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="book-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<p>
<?= Html::a('Create Book', ['create'], ['class' => 'btn btn-success']) ?>
</p>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'name',
[
'attribute' => 'author',
'value' => 'author.name',
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
</div>
Author Model:
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "author".
*
* #property integer $id
* #property string $name
*/
class Author extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'author';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['name'], 'required'],
[['name'], 'string', 'max' => 200]
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
];
}
}
I think I may have to change something somehwhere in the author/authorSearch model.
Can someone help
thanks
You can also add columns to a gridview with value from an anonymous function as described here http://www.yiiframework.com/doc-2.0/yii-grid-datacolumn.html#$value-detail. For example you can show an author's name like this in a gridview:
<?= GridView::widget([
'dataProvider'=>$dataProvider,
'filterModel'=>$searchModel,
'columns'=>[
[
'attribute'=>'author.name',
'value'=>function ($model, $key, $index, $column) {
return $model->author->name;
},
],
//...other columns
]);
?>
you can also return a html-link to the detail-view of an author like this:
//...
'columns'=>[
[
'attribute'=>'author',
'value'=>function ($model, $key, $index, $column) {
return Html::a($model->author->name, ['/author/view', 'id'=>$model->author->id]);
},
],
//...
],
//...
You can access relation table data in any crud view file using their relation name. $model->relName->attribute_name.
And You can access relation table data in gridview at following way :
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
[
'attribute' => 'author',
'value'=>'author.author_name', //relation name with their attribute
]
],
]);
First you need a get function in your model, but you have.
This is :
public function getAuthor()
{
return $this->hasOne(Author::className(), ['id' => 'author']);
}
Now you just need do one more thing.
Go to the index file, and to GridView, and columns.
Write this into columns:
[
'attribute' => 'author',
'value' => 'author.name',
],
In the value, the first parameter is your Get function, what named is : getAuthor, and . after your column name.
Hello in your BookSearch Mode please add below code like this.
$query->joinWith(array('author'));
$query->andFilterWhere(['id' => $this->id,])
->andFilterWhere(['like', 'author.author_name', $this->author]);
And in your view file please use below given code below code is for view file inside grid attrubute.
[
'attribute' => 'author',
'value' => 'author.name',
]
i hope this will helps you. and i hope in author table name is stored in name column.
This worked for me - inside the BookSearch Model:
public function search($params)
{
$dataProvider = new \yii\data\SqlDataProvider([
'sql' => 'SELECT book.id as id ,book.author_fk, book.name as book_name , author.name as author_name' .
' FROM book ' .
'INNER JOIN author ON (book.author_fk = author.id) '
]);
$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;
}
return $dataProvider;
}
Only issue now is getting the ActionColumn to work correctly, they're currently linking to the wrong IDs, help anyone.

Categories