I am trying to combine 3 tables in the my ActiveRecord Search().
I have this table
employees
id
first_name
projects
id
name
project_assignment
id
employee_id
project_id
date_added
date_removed
I am using GridView to display all the employees in my database.
Now, I wanted to display project where the employee is being assigned. So having said this, obviously we need these 3 tables to connect.
In my Employees.php Model, i have this code:
public function getproject_assignment()
{
return $this->hasMany(ProjectAssignment::className(), ['employee_id' => 'id']);
}
In my ProjectAssignment.php model
/**
* #return \yii\db\ActiveQuery
*/
public function getEmployee()
{
return $this->hasOne(Employees::className(), ['id' => 'employee_id']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getProject()
{
return $this->hasOne(Projects::className(), ['id' => 'project_id']);
}
In my EmployeeSearch.php
class EmployeesSearch extends Employees
{
public $project_name;
public function rules()
{
return [
[['id', 'employment_status_id'], 'integer'],
[['project_name','string_id', 'first_name', 'last_name', 'middle_name', 'gender', 'birth_date', 'civil_status', 'phone', 'address', 'zip', 'email', 'position', 'start_date', 'tin', 'philhealth', 'sss', 'hdmf', 'photo_location'], 'safe'],
];
}
public function search($params)
{
$query = Employees::find();
$query->addSelect(['projects.name as project_name','employees.*']);
$query->leftJoin('project_assignment','project_assignment.employee_id = employees.id');
$query->leftJoin('projects','projects.id = project_assignment.project_id');
$query->andWhere([
'project_assignment.date_removed' => NULL
]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => array('pageSize' => 20),
]);
$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,
]);
$query->andWhere([
'employees.deleted_at' => NULL
// 'projects.deleted_at' => NULL
]);
$query->andFilterWhere(['like', 'string_id', $this->string_id])
->andFilterWhere(['like', 'first_name', $this->first_name])
->andFilterWhere(['like', 'last_name', $this->last_name])
->andFilterWhere(['like', 'middle_name', $this->middle_name])
->andFilterWhere(['like', 'gender', $this->gender])
->andFilterWhere(['like', 'civil_status', $this->civil_status])
->andFilterWhere(['like', 'phone', $this->phone])
->andFilterWhere(['like', 'address', $this->address])
->andFilterWhere(['like', 'zip', $this->zip])
->andFilterWhere(['like', 'email', $this->email])
->andFilterWhere(['like', 'position', $this->position])
->andFilterWhere(['like', 'tin', $this->tin])
->andFilterWhere(['like', 'philhealth', $this->philhealth])
->andFilterWhere(['like', 'sss', $this->sss])
->andFilterWhere(['like', 'hdmf', $this->hdmf])
->andFilterWhere(['like', 'photo_location', $this->photo_location]);
return $dataProvider;
}
In my index.php (view file)
$gridColumns = [
[
'attribute' => 'Project',
'value' => 'projects', //the value means that this is the value of the column
//the zip here is the get parameter
'filter' => Html::activeDropDownList($searchModel, 'project_name', ArrayHelper::map(\app\models\Projects::find()->asArray()->all(), 'id', 'name'),['class'=>'form-control','prompt' => 'Select Project']),
],
'first_name',
'middle_name',
'last_name',
// 'position',
[
'attribute' => 'position',
'value' => 'position',
'filter' => Html::activeDropDownList($searchModel, 'position', ArrayHelper::map(Employees::find()->groupBy('position')->asArray()->all(), 'position', 'position'),['class'=>'form-control','prompt' => 'Select Position']),
],
['class' => 'yii\grid\ActionColumn',
'template' => '{update} {delete}'],
];
<?php echo
GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => $gridColumns,
'export' => [
'fontAwesome' => true,
]
]);
?>
The problem here is the Project column is not displaying anything.
Here's a screenshot:
When I checked on Yii Debuger, this sql query has been ran:
SELECT `projects`.`name` AS `project_name`, `employees`.* FROM `employees` LEFT JOIN `project_assignment` ON project_assignment.employee_id = employees.id LEFT JOIN `projects` ON projects.id = project_assignment.project_id WHERE (`project_assignment`.`date_removed` IS NULL) AND (`employees`.`deleted_at` IS NULL) LIMIT 20
This query is correct and what I was expecting. The only problem is that the Project column is not displaying as the screenshot that i showed you above.
I am not sure how to make this work. Been scratching my head for a couple of hours already.
Any help please. Thank You!
'value' => 'projects', //the value means that this is the value of the column
Actually the value here can be string or closure. If it is a string then it means that a string representing the attribute name to be displayed in this column as documentation says. Try to use closure. In your case it will be like this:
'value' => function ($model, $key, $index, $column){
return $model->project->name;
}
for kartik\grid\GridView;
'class' => 'kartik\grid\EditableColumn',
'attribute'=>'myAttribute',
'header' => 'myHeader',
'editableOptions' => [
'inputType' => \kartik\editable\Editable::INPUT_TEXT,
'valueIfNull' => '-',
/**
* #var string the value to be displayed. If not set, this will default to the attribute value. If the attribute
* value is null, then this will display the value as set in [[valueIfNull]].
*/
public $displayValue;
Related
I want to keep sorting enabled on all columns but disable filtering on few specif fields.
For example, I want to disable filtering on first_name column but enable sorting on the same column. How can I do that?
Following code disables the sorting and filtering both.
My code for GridView is:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
[
'attribute'=>'First Name',
'value'=> 'first_name',
'filter'=>false,
//'enableSorting'=>true
],
//'first_name',
'last_name',
'street',
'zipcode',
'company',
'created_at',
],
],
]); ?>
Also my search function code in the CustomerSearchModel::
public function search($params)
{
$query = Customer::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
//'sort' => ['attributes' => ['first_name','last_name','street','zipcode','company','created_at']],
]);
$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,
'discount' => $this->discount,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]);
$query->andFilterWhere(['like', 'first_name', $this->first_name])
->andFilterWhere(['like', 'last_name', $this->last_name])
->andFilterWhere(['like', 'street', $this->street])
->andFilterWhere(['like', 'zipcode', $this->zipcode])
->andFilterWhere(['like', 'company', $this->company]);
return $dataProvider;
}
Just remove the filter model in the grid view configuration if you'd like to remove all search inputs:
'filterModel' => null,
You should than be able to remove not required $query->andFilterWhere() declarations in your CustomerSearchModel.
If you'd like to remove only certain search inputs, tell the search model that an attribute is not 'active' within the rules:
class CustomerSearchModel {
...
public function rules() {
return [
// removed 'first_name' from the safe attributes:
[['last_name','street','zipcode','company','created_at'], 'safe'], // <--- 'safe'
];
}
...
}
Though 'safe' needs to be used for the declaration, I wrote 'active' since the GridView calls DataColumn::renderFilterCellContent() (source code: here) which checks if an attribute is an active one with $model->isAttributeActive($this->attribute). And those are the ones that are part of the current scenario (the above rule declaration is for the default scenario, attributes marked as 'safe' will be the active ones).
With this you don't need to add 'filter' => false to the column definition. The standard configuration should be sufficient now:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'first_name',
'last_name',
'street',
'zipcode',
'company',
'created_at',
],
],
]); ?>
The filter input for first_name will disappear and the sort option still exists.
i want to join my company table name to employee id. here my code in
employee model
public function attributeLabels()
{
return [
'id' => 'ID',
//'company_id' => 'Company ID',
'emp_name' => 'Emp Name',
'emp_email' => 'Emp Email',
'emp_salery' => 'Emp Salery',
];
}
public function getCompany()
{
return $this->hasOne(Company::className(),['id' => 'company_id']);
}
in index file i use this code
<?php PJax::begin();?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
//['class' => 'yii\grid\SerialColumn'],
//'id',
[
'attribute' => 'company_id',
'value' => 'company.name',
],
'emp_name',
'emp_email:email',
'emp_salery',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
<?php PJax::end();?></div>
in employee search table i use this code
public function search($params)
{
$query = Employee::find();
$query->joinWith(['company']);
// 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,
]);
$query->andFilterWhere(['like', 'company_id', $this->company_id])
->andFilterWhere(['like', 'emp_name', $this->emp_name])
->andFilterWhere(['like', 'emp_email', $this->emp_email])
->andFilterWhere(['like', 'emp_salery', $this->emp_salery])
->andFilterWhere(['like', 'Company.name', $this->company_id])
->andFilterWhere(['like', 'company.name', $this->company])
;
return $dataProvider;
}
http://localhost/test/web/employee/
is shows in company field (not set)
pls help me
you can do this in two difference way : 1 . If you want use active record you must set property in first model you want to select it and join table with that like:
public $pin;
then when you get data you can access to pin in second table
the second way is you use asArray() that return all off data in both table
$model = News::find()->leftJoin('comment', 'news.id = comment.news_id')->asArray()->all();
then you can use it in your gridview
You should add a getter eg:getCompanyname()n your base model
......
public function attributeLabels()
{
return [
'id' => 'ID',
//'company_id' => 'Company ID',
'emp_name' => 'Emp Name',
'emp_email' => 'Emp Email',
'emp_salery' => 'Emp Salery',
'companyName' => 'Company Name')
];
}
public function getCompany()
{
return $this->hasOne(Company::className(),['id' => 'company_id']);
}
You should add a getter for company name
/*
Getter for company name
*/
public function getCommpanyName() {
return $this->company->name;
}
and in your gridview you should use the new get name (companyName)
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
'companyName',
'emp_name',
'emp_email:email',
'emp_salery',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
see this for more complete samples
http://www.yiiframework.com/wiki/621/filter-sort-by-calculated-related-fields-in-gridview-yii-2-0/
I have a football match function. But always display same team on home or away.
Here's my code,
Model [Match] :
use app\models\Team;
...
public function getTeam()
{
return $this->hasOne(Team::className(), ['id' => 'home', 'id' => 'away']);
}
...
Team model is list of all team
Match table only keep id of Team on Home Field and Away Field
Model [MatchSearch] :
....
public $team_home;
public $team_away;
public function rules()
{
return [
[['home', 'away'], 'integer'],
[['team_home', 'team_away'], 'safe'],
];
}
...
public function search($params)
{
$query = Match::find()->joinWith(['team']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->sort->attributes['team_home'] = [
'asc' => ['team.team' => SORT_ASC],
'desc' => ['team.team' => SORT_DESC],
];
$dataProvider->sort->attributes['team_away'] = [
'asc' => ['team.team' => SORT_ASC],
'desc' => ['team.team' => SORT_DESC],
];
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
$query->andFilterWhere([
'home' => $this->home,
'away' => $this->away,
]);
$query->andFilterWhere(['like', 'team.team', $this->team_home])
->andFilterWhere(['like', 'team.team', $this->team_away]);
return $dataProvider;
}
Views [Index] :
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
[
'attribute' => 'home',
'value' => function($data) {
return $data->team->team;
},
],
[
'attribute' => 'away',
'value' => function($data) {
return $data->team->team;
},
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
<?php Pjax::end(); ?>
But the result always show the Away team both Home or Away :
Home :
Team Away
Away :
Team Away
How to fix this?
You can use inner join
$query = Match::find()
->innerJoin('team_tname as home', '`team_taame`.`id` = `match_table_name`.`home`')
->innerJoin('team_taname as away', '`team_name`.`id` = `match_table_name`.`away`');
the you should refer to the column name using the proper table alias
I have some problems in making modelsearch in yii2.
Here's is my table's relation
I want to display Jurusan from table aitambah to ais3 and I want to display NamaMahasiswa from table ai to ais3. I made table s3penghubung so that table aitambah can be related to ais3. I was able to display them. But, when I try to type "71501" in "NRP" field, the searching not working properly. it is refreshing the page. there is no any change to the rows displayed. so, what should I do to fix that?
here is my modelsearch codes:
<?php
namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Ais3;
/**
* Ais3Search represents the model behind the search form about `app\models\Ais3`.
*/
class Ais3Search extends Ais3
{
/**
* #inheritdoc
*/
public function rules()
{
return [
[['id', 'kode'], 'integer'],
[['NRP', 'namaMahasiswaText', 'ProgramStudi', 'TanggalMasuk', 'TanggalKeluar'], 'safe'],
];
}
public $NamaMahasiswa;
public $namaMahasiswaText;
/**
* #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 = Ais3::find();
$query->joinWith('ai');
// 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,
'kode' => $this->kode,
]);
$query->andFilterWhere(['like', 'ais3.NRP', $this->NRP])
->andFilterWhere(['like', 'ai.NamaMahasiswa', $this->namaMahasiswaText])
->andFilterWhere(['like', 'ais3.ProgramStudi', $this->ProgramStudi])
->andFilterWhere(['like', 'ai.TanggalMasuk', $this->TanggalMasuk])
->andFilterWhere(['like', 'ais3.TanggalKeluar', $this->TanggalKeluar]);
return $dataProvider;
}
}
here is mygridview codes
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
//'id',
'NRP',
'namaMahasiswaText',
'ProgramStudi',
//'TanggalMasuk',
[
'attribute' => 'TanggalMasuk',
'value' => function($data) {
return $data->ai->TanggalMasuk;
},],
'TanggalKeluar',
//YANG DITAMBAH
[
'attribute'=>'NRP',
'value'=>'s3penghubung.aitambah.JURUSAN',
'label' => 'Jurusan',
],
[
'attribute'=>'NRP',
'value'=>'s3penghubung.aitambah.NAMKANTOR',
'label' => 'Nama Kantor',
],
[
'attribute'=>'NRP',
'value'=>'s3penghubung.aitambah.ANGKATAN',
'label' => 'Angkatan',
],
[
'attribute'=>'NRP',
'value'=>'s3penghubung.aitambah.TELP',
'label' => 'Nomor HP/Telp',
],
[
'attribute'=>'NRP',
'value'=>'s3penghubung.aitambah.PEKERJAAN',
'label' => 'Pekejaan',
],
[
'attribute'=>'NRP',
'value'=>'s3penghubung.aitambah.EMAIL',
'label' => 'Email',
],
[
'attribute'=>'NRP',
'value'=>'s3penghubung.aitambah.KODEPROP',
'label' => 'KodeProp',
],
// 'kode',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
I thought there must be something wrong in my query filter
$query->andFilterWhere(['like', 'ais3.NRP', $this->NRP])
->andFilterWhere(['like', 'ai.NamaMahasiswa', $this->namaMahasiswaText])
->andFilterWhere(['like', 'ais3.ProgramStudi', $this->ProgramStudi])
->andFilterWhere(['like', 'ai.TanggalMasuk', $this->TanggalMasuk])
->andFilterWhere(['like', 'ais3.TanggalKeluar', $this->TanggalKeluar]);
but I dont know how to fix those codes. Could you please help me to solve this? Thankyou
The right answer is here:
here's gridview in index
and here's in modelsearch
thankyou ck_anjuk for solving my problem.
I have a problem with Yii2 pagination. I use ListView widget to show data. Also I am using SetSort in my model to sort data.
My search model code:
public function search($params)
{
$query = Items::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->setSort([
'defaultOrder' => ['position' => SORT_ASC],
'attributes' => [
'position' => [
'asc' => ['items.is_top'=>SORT_ASC,'items.position' => SORT_DESC],
'label' => 'By popularity',
],
'pricerup' => [
'asc' => ['prices.price' => SORT_ASC],
'label' => 'Exprensive to cheap'
],
'pricerdown' => [
'asc' => ['prices.price' => SORT_DESC],
'label' => 'Cheap to expensive'
],
]
]);
if (!($this->load($params) && $this->validate())) {
$query->joinWith(['prices']);
return $dataProvider;
}
$query->andFilterWhere([
'discount' => $this->discount,
'present_id' => $this->present_id,
'is_top' => $this->is_top,
'manufacturer_id' => $this->manufacturer_id,
]);
$query->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'description', $this->description])
->andFilterWhere(['like', 'taste', $this->taste])
->andFilterWhere(['like', 'country', $this->country])
->andFilterWhere(['like', 'slug', $this->slug])
->andFilterWhere(['like', 'short_desc', $this->short_desc])
->andFilterWhere(['like', 'thumbnail', $this->thumbnail]);
return $dataProvider;
}
I know that this is not a very good decision to divide DESC and ASC logic for price, but this is needed for current design. My controller code:
public function actionIndex()
{
$searchModel = new ItemsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->getQueryParams());
return $this->render('index', [
'dataProvider'=>$dataProvider,
'searchModel'=>$searchModel,
]);
}
As I said, in view I use ListView. This is my view code:
<? Pjax::begin(['id' => 'items', 'clientOptions' => ['method' => 'POST']]);?>
<?
$dataProvider->pagination = [
'defaultPageSize' => 8,
];
echo ListView::widget( [
'id'=>'items',
'pager' => [
'firstPageLabel' => "",
'disabledPageCssClass'=>'swiper-button-disabled',
'lastPageLabel' => "",
'nextPageLabel' => ">",
'prevPageLabel' => "<",
'maxButtonCount'=>0,
'nextPageCssClass'=>'total-button-next', 'prevPageCssClass'=>'total-button-prev',
'options'=>['id'=>'poplinks','class'=>'col-md-12 total-slider-orders margin-right-null padding-left-right-yes total-down-arrow']
],
'dataProvider' => $dataProvider,
'itemView' => '_item',
'summary'=>'',
] );
Pjax::end();?>
As a result I get something like this:
As you can see, it doesn't have last element on the first page, on the next pages everything is ok. I think that this is something with the offset,limit. Can someone tell me, where is an error? Thanks!
Because of many relation, AR show item with two prices as two items, so it show 7 items on page instead of 8. Resolved it just by adding to search model one line:
$query->groupBy('items.id');