Counting records from related tables Gridview - php

I have 3 tables named hostgroup, host and services.
I have a database like this for example.
Hostgroup:
id, name
1 GroupA
2 GroupB
Host:
id, name, hostgroup_id
1 HostA 1
2 HostB 1
3 HostC 2
4 HostD 2
5 HostE 2
//2 = critical, 1 = warning
Service:
id, host_id, state
1 1 2
2 1 2
3 2 1
4 2 1
5 3 2
The final table should be like this:
Name Total Hosts Total Critical Total Warning
GroupA 2 2 2
GroupB 3 1 0
I was able to do the 2nd column which is Total Hosts by adding this function on my Hostgroup model:
public function getHostcount()
{
return Host::find()->where(['hostgroup_id' => $this->id])->count();
}
How can I count the total warning and critical also?
Total critical (counts the number of total critical status of hosts related to the hostgroup)
Total warning (counts the number of total warning status of hosts related to the hostgroup)
EDIT: ADDED SOURCE CODE
HostgroupSearch model:
<?php
class HostgroupSearch extends Hostgroup
{
public function rules()
{
return [
[['id', 'check_interval', 'retry_interval', 'max_check_attempts', 'timeout', 'freshness_threshold', 'is_auto_recovery', 'reflect_flg', 'created_user_id'], 'integer'],
[['object_name', 'name', 'name_search', 'remarks', 'snmp_community', 'timestamp'], 'safe'],
];
}
public function search($params)
{
$query = Hostgroup::find();
$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,
'check_interval' => $this->check_interval,
'retry_interval' => $this->retry_interval,
'max_check_attempts' => $this->max_check_attempts,
'timeout' => $this->timeout,
'freshness_threshold' => $this->freshness_threshold,
'is_auto_recovery' => $this->is_auto_recovery,
'reflect_flg' => $this->reflect_flg,
'created_user_id' => $this->created_user_id,
'timestamp' => $this->timestamp,
]);
$query->andFilterWhere(['like', 'object_name', $this->object_name])
->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'name_search', $this->name_search])
->andFilterWhere(['like', 'remarks', $this->remarks])
->andFilterWhere(['like', 'snmp_community', $this->snmp_community]);
return $dataProvider;
}
}
This HostlistController controls the display of everything in my table.
<?
class HostlistController extends Controller
{
public $layout = "default";
public function actionIndex()
{
$searchModel = new HostgroupSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
}
?>
This is then my view page index.php:
'columns' => [
[
'label' => 'Name',
'attribute' => 'name',
'format' => 'raw',
'value' => function ($data, $id) {
return Html::a($data->name, '/index.php/hostlistbygroup/'. $id);
},
],
[
'label' => 'Total Host',
'attribute' => 'hostcount',
],
[
'label' => 'Total Critical',
'attribute' => 'host.criticalcount',
],
[
'label' => 'Total Warning',
'attribute' => 'host.warningcount',
],

Nevermind. Solved it by adding these functions to Host model.
public function getCriticalcount()
{
return ServiceStatuses::find()->where(['host_id' => $this->id, 'last_hard_state' => '2'])->count();
}
public function getWarningcount()
{
return ServiceStatuses::find()->where(['host_id' => $this->id, 'last_hard_state' => '1'])->count();
}
and added this to Hostgroup model
public function getHost()
{
return $this->hasOne(Host::className(), ['hostgroup_id' => 'id']);
}
modified index.php with this
'columns' => [
[
'label' => 'Name',
'attribute' => 'name',
'format' => 'raw',
'value' => function ($data, $id) {
return Html::a($data->name, '/index.php/hostlistbygroup/'. $id);
},
],
[
'label' => 'Total Host',
'attribute' => 'hostcount',
],
[
'label' => 'Total Critical',
'attribute' => 'host.criticalcount',
],
[
'label' => 'Total Warning',
'attribute' => 'host.warningcount',
],

Related

GridView filter model in Yii2

I have a gridview with a dataprovider which has joined two tables as query:
$applicationDataProvider = new ActiveDataProvider([
'query' => Application::find()->with('applicantInfo')
->where(['job_posting_id' => $jobPosting->id,
'deleted_flag' => 0])->orderBy('created_at desc'),
'pagination' => [
'pageSize' => 5
]
]);
and here is my GridView:
<?= GridView::widget([
'dataProvider' => $applicationDataProvider,
'filterModel'=>$searchModel,
'columns' => [
'id',
[
'class' => yii\grid\DataColumn::className(),
'headerOptions' => ['style' => 'color:#337ab7'],
'header' => 'სახელი',
'label'=>'name',
'value' => function ($data) {
return $data->applicantInfo->first_name . ' ' . $data->applicantInfo->last_name;
}
],
'applicantInfo.email',
'applicantInfo.phone',
'created_at:date',
[
'class' => 'yii\grid\ActionColumn',
'headerOptions' => ['style' => 'color:#337ab7'],
'template' => '{view}',
'buttons' => [
'view' => function ($url, $model) {
return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', $url, [
'title' => Yii::t('app', 'გახსნა'),
]);
}
],
'urlCreator' => function ($action, $model, $key, $index) {
if ($action === 'view') {
$url = '/app-info/?id=' . $model->id;
return $url;
}
}
...
in a search model I have email field only because I want to gridview has just only email search field.
class ApplicationSearch extends Application
{
public function rules()
{
return [
[['email'], 'safe'],
];
}
but here is not drawn search field for email, how can I fix it?
You need to add email attribute to ApplicationSearch to store value from filter:
class ApplicationSearch extends Application {
public $email;
public function rules() {
return [
[['email'], 'safe'],
];
}
}
Use this attribute for filtering:
$applicationDataProvider = new ActiveDataProvider([
'query' => Application::find()->with('applicantInfo')
->where(['job_posting_id' => $jobPosting->id, 'deleted_flag' => 0])
->andFilterWhere(['like', 'applicantInfo.email', $this->email])
->orderBy('created_at desc'),
'pagination' => [
'pageSize' => 5
]
]);
And use value from relation in grid:
// ...
[
'attribute' => 'email',
'value' => function ($data) {
return $data->applicantInfo->email;
},
],
'applicantInfo.phone',
// ...

Yii2: display some records at the top of GridView widget

In Yii2 app I have model Document which can belong to user. Belonging is set with owner_id field.
In view I display list of Documents using GridView widget. Default sort is by document_id.
Every user sees all documents (event if specific document doesn't belong to him).
But I need to display documents which belongs to current logged in user at the top of GridView. How can I do this?
I suppose I should make some changes to Document::search() method by can't find out what excactly I should do.
Here is my controller action:
public function actionIndex()
{
$modelFullName = $this->modelFullName;
$model = new $modelFullName();
$dataProvider = $model->search(Yii::$app->request->queryParams);
return $this->render(
'index',
[
'model' => $model,
'dataProvider' => $dataProvider,
]
);
}
Part of view:
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $model,
'columns' => [
[
'attribute' => 'document_id',
],
[
'attribute' => 'status',
'format' => 'raw',
'value' => function($model) {
return $model->statusString;
},
],
[
'attribute' => 'title',
],
[
'attribute' => 'date_created'
],
[
'attribute' => 'client_id',
'value' => function($model) {
return $model->client ? $model->client->title : '';
},
'filter' => ArrayHelper::map(Clients::find()->all(), 'client_id', 'title')
],
[
'attribute' => 'project_id',
'value' => function($model) {
return $model->project ? $model->project->title : '';
},
'filter' => ArrayHelper::map(Projects::find()->all(), 'project_id', 'title')
],
[
'class' => yii\grid\ActionColumn::className(),
'template' => '{view} {delete}',
'buttons' => [
'view' => function ($url, $model) {
return $this->context->getBtn('view', $model);
},
'delete' => function ($url, $model) {
if (Yii::$app->user->can('deletePrsSum')) {
return $this->context->getBtn('delete', $model);
}
},
],
'visibleButtons' => [
'update' => Yii::$app->user->can('updateDocument'),
'delete' => Yii::$app->user->can('deleteDocument'),
]
],
],
]);
Current Document::search() implementation:
public function search($params)
{
$query = self::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [
'defaultOrder' => ['document_id' => SORT_ASC]
]
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
if ($this->client_id) {
$query->andFilterWhere([
'client_id' => $this->client_id,
]);
}
if ($this->project_id) {
$query->andFilterWhere([
'project_id' => $this->project_id,
]);
}
return $dataProvider;
}
UPDATE
So how I managed to do this:
public function search($params)
{
$userId = Yii::$app->user->identity->user_id;
$query = self::find()->select(
"*, IF(owner_id={$userId},(0),(1)) as sort_order"
)->orderBy([
'sort_order' => SORT_ASC,
'document_id' => SORT_ASC
]);
//further code...
Add a filter in your search function to filter with the id of the logged in person/user:
$query->andFilterWhere(['owner_id' => Yii::$app->user->identity->id]);

how to join table in grid view in yii2

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/

YII2 - How to Display Defferent Value of Two Relation on Same Table

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

Sort by related model attributes in GridView Yii Framework 2.0

I have Post model and two related models, User and Comments.
Relation with User and Comment model defined in Post model:
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
public function getUserName()
{
return $this->user->name;
}
public function getComments(){
return $this->hasMany(Comment::className(), ['comment_id' => 'id']);;
}
public function countCommentPoints() {
return $this->hasMany(Comment::className(), ['comment_id' => 'id'])->sum('point');
}
My PostSearch model looks like following. I omitted the code andFilterWhere() because it is out of the scope:
class PostSearch extends Post {
public $userName;
public function rules()
{
return ['userName', 'safe'];
}
public function search($params) {
$query = Post::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->setSort([
'attributes' => [
'userName' => [
'asc' => ['user.name' => SORT_ASC],
'desc' => ['user.name' => SORT_DESC],
],
],
]);
if (!($this->load($params) && $this->validate())) {
$query->joinWith(['user']);
return $dataProvider;
}
}
return $dataProvider;
}
View code:
echo GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'id',
'title',
[
'attribute' => 'userName',
'value' => 'userName',
'label' => 'User Name'
],
[
'attribute' => 'comment',
'value' => function($model){
return $model->countCommentPoints();
},
'label' => 'Points',
],
],
]);
With all the code above I could sort the records by id and title and by userName which is an attribute of the related User model. But I could not sort by the column Points since it is not an attribute of the Comment model but a sum value returned from the getLeadEarningPerWebmaster() method. I have tried to read Yii 2.0 documentation here http://www.yiiframework.com/doc-2.0/guide-output-data-widgets.html but the section Sorting Data is still under development. How can I make GridView sort by the Points column?
You can sort GridView columns by related columns that are not necessarily inside the original ActiveRecord.
echo GridView::widget([
'dataProvider' => new ActiveDataProvider([
'query' => $model->joinWith([
'comment' => function ($query) {
$query->select('SUM(point) AS sum')->from(['comment' => '{{%comment}}']);
}
]),
'sort' => [
'attributes' => [
'comment.sum' => [
'asc' => ['comment.sum' => SORT_ASC],
'desc' => ['comment.sum' => SORT_DESC],
]
],
'sortParam' => 'post-sort',
'defaultOrder' => ['comment.sum' => SORT_ASC]
],
]),
That should get you started.

Categories