I have a GridView which displays an employee's summary of his/her payslip. Here's a screenshot for more understanding:
Those highlighted columns come from a different model which is the User model while the rest come from the Payslip model.
How do I merge 2 models in one GridView? Because in GridView, it is more likely for you to have a single model to display data. But how about 2 models?
Here's a code in my Payslip model, note that getUser() is generated with gii since user_id is a foreign key in my payslip table:
public function getUser()
{
return $this->hasOne(User::className(), ['user_id' => 'user_id']);
}
public function getFirstName()
{
return $this->user ? $this->user->fname : 'First Name';
}
public function getLastName()
{
return $this->user ? $this->user->lname : 'Last Name';
}
The Payslip controller:
public function actionIndex()
{
$searchModel = new PayslipSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
And then the Payslip view:
<?php
echo GridView::widget([
'dataProvider' => $dataProvider,
//'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'payslip_id',
//'store_id',
'firstName',
'lastName',
'total_earnings',
'total_deduction',
'net_pay',
['class' => 'yii\grid\ActionColumn'],
],
]);
?>
BTW, in this example, I just created payslip #1 manually to give you a demo.
Additional info:
The logged in user is a BizAdmin user, and all of BizAdmin's staff users should be displayed in the payslip table (that table above) even if these staff users still don't have any payslip created for them. So by default, that table will be occupied already with staff users under the logged in BizAdmin user, and those staff users who still have no payslips created will be indicated "Create Payslip"
Here's an example in KashFlow:
Update view to:
<?php
echo GridView::widget([
'dataProvider' => $dataProvider,
//'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'payslip_id',
//'store_id',
['value' => function ($data) {return $data->getFirstName();}, 'label' => 'First Name'],
['value' => function ($data) {return $data->getLastName();}, 'label' => 'LastName'],
'total_earnings',
'total_deduction',
'net_pay',
['class' => 'yii\grid\ActionColumn'],
],
]);
?>
And in $searchModel->search add you relation, like that:
$query = Payslip::find()->with(['user']);
Read for data column - http://www.yiiframework.com/doc-2.0/guide-output-data-widgets.html#data-column
Related
I want to multiply two columns in the yii2 grid the grid view is as follows
<?= GridView::widget([
//'dataProvider' => $dataProvider,
'dataProvider'=>new ActiveDataProvider([
'query' => Adanalytics::find()->
where(['publisher_id' => Yii::$app->user->identity->id ])->
select('id,ad_id,MAX(impression) AS impression, MAX(view) AS view, MAX(clicks) AS clicks,MAX(cpc) AS cpclick,MAX(cpv) AS cpview, (MAX(clicks)*MAX(cpc)) AS totalccost')->
groupBy('ad_id, visitor_ip'),
]),
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
//'id',
'ad_id',
//'advertiser_id',
//'publisher_id',
//'visitor_ip',
//'type_ad',
'impression',
'view',
'clicks',
//'placed_date',
//'cpc',
//'cpv',
'cpclick',
'cpview',
'totalccost',
//'cpi',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
But it is not giving me the desired output where am I going wrong how can i do this?
If you need the column only as display value in the gridview you can create a calculated column.
'cpview',
[
'label' => 'Totalcost',
'value' => function($model){
return $model->cpclick * $model->clicks;
}
],
Or else you can add at the start of your Adanalytics class
public $totalccost;
if you want to use the calculation anywhere you can do following.
in your model
public function getTotalcost()
{
return $this->clicks * $this->cpclick;
}
and you can label to this attribute
public function attributeLabels()
{
return [
...
'totalcost' => Yii::t('app', 'Total cost'),
];
}
in grid view column
...
'cpview',
'totalcost'
You can use this function anywhere as $model->totalcost
I have solved the problem by using yii2 db query which is like this way.
$subquery = Adanalytics::find()->
select('id,ad_id,date_event,max(cpc) cpclick,max(cpv) cpview,max(impression) impression,max(view) view,max(clicks) clicks,visitor_ip,publisher_id')->
from('ad_analytics')->
where(['publisher_id' => Yii::$app->user->identity->id ])->
groupBy('ad_id,date_event,visitor_ip');
$query=Adanalytics::find()->
select('ad_id,date_event,sum(cpclick) total_click_cost,sum(cpview) total_view_cost,sum(impression) total_impression,sum(view) total_views,sum(clicks) total_clicks,publisher_id')->
from(['t'=>$subquery])->
groupBy('t.ad_id,t.date_event');
And called the column in grid view.
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'ad_id',
'total_impression',
'total_views',
'total_clicks',
'total_click_cost',
'total_view_cost',
'date_event',
['class' => 'yii\grid\ActionColumn'],
],
Defined them in model before calling.
public $total_click_cost;
public $total_view_cost;
public $total_impression;
public $total_views;
public $total_clicks;
i'm developing a web application with Yii2 framework, and i'm facing a problem right now. I want to display the data from a many-to-many relation in a gridview and be able to filter from those fields later on.
I've read the official documentation here, some stackoverflow post like this and other resources but can't seem to get it to work. I have 3 tables: actividad, plan_actividad and circulo_icare, actividad is related to plan_actividad and circulo_icare is also related to it (plan_actividad is the junction table). So i have defined the following relations in my Actividad model:
class Actividad extends \yii\db\ActiveRecord
{
....
public function getPlanActividad()
{
return $this->hasMany(PlanActividad::classname(), ['act_id' => 'act_id']);
}
public function getCirculo()
{
return $this->hasMany(CirculoIcare::classname(), ['cirica_id' => 'act_id'])->via('planActividad');
}
...
}
The in my view index.php i'm trying to show the values in a gridview like this:
<?= GridView::widget([
'dataProvider' => $dataProvider,
// 'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// 'act_id',
['attribute' => 'Codigo Evento', 'value' => 'act_numorden'],
['attribute' => 'Nombre Evento', 'value' => 'act_nombre'],
['attribute' => 'Fecha Evento', 'value' => 'act_fecha'],
['attribute' => 'Locacion', 'value' => 'locacion.loc_nombre'],
[
'attribute' => 'Circulo',
'value' => 'circulo.cirica_nombre',
],
['attribute' => 'Circulo id',
'value' => 'planActividad.cirica_id',
],
// 'act_horaini',
// 'act_horafin',
// 'act_idencuesta',
// 'act_vigencia:boolean',
// 'loc_id',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
The problem is, i can't get any values to show with the circulo relation, it always shows (not set). If i change hasMany in getPlanActividad() with hasOne() then it shows some values (only 2 of 11 it should, based on the cirica_id that exist on plan_actividad table) but these are not correct anyway. I know that i can filter for those fields later on in search view but i don't really understand why the relations doesn't work as i expected.
Any help would be greatly appreciated, let me know if more info is needed and thank you in advance.
Answering my own question (credits to softark from the yii official forums).
In order for the relation to work as expected, I had to change:
public function getCirculos()
{
return $this->hasMany(CirculoIcare::classname(), ['cirica_id' => 'act_id'])->via('planActividad');
}
to
public function getCirculos()
{
return $this->hasMany(CirculoIcare::classname(), ['cirica_id' => 'cirica_id'])->via('planActividad');
}
and use a callback function in the gridview to display the correct values, since a hasMany relation gives an array of models and not a single model. So I modified the gridview code to:
<?= GridView::widget([
'dataProvider' => $dataProvider,
// 'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
...
['attribute' => 'circulo',
'value' => function($model){
$items = [];
foreach($model->circulos as $circulo){
$items[] = $circulo->cirica_nombre;
}
return implode(', ', $items);
}],
...
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
This gives the expected results. You can then apply filter by the relation fields easily by adapting the search model.
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);
Hi I have 2 tables and models for them. First of them is
User
and second
News
I want to take user id from table News and draw her name and surname. There is printscreen of table News:
I am trying to use the function:
public function getUrUser()
{
$q= News::find()->where(['urUser_Id' =>'Id'])->one();
$RoyalUserData=User::findOne($q);
//$RoyalUserData= User::find()->where(['Id' => $q])->one();
return $RoyalUserData->Name;
}
But this doesnt work. Only when I prescribe to q value 3 for egzample then it work. I know that is the wrong code in my first line of my function probably. I know that is easy but I am a beginner and I've fought with the code for about 1 hour. Can anyone help me?
In my view I use this:
<?=$model->getUrUser();?>
And I use this in ListView.
My controller:
public function actionIndex()
{
$model = new NewsForm();
$searchModel = new NewsSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->setSort(['defaultOrder' => ['Id'=>SORT_DESC]]);
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->saveNews();
return $this->redirect(['/content/news']);
} else {
return $this->render('index', [
'model' => $model,
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
}
My index where i use _item:
echo ListView::widget( [
'dataProvider' => $dataProvider,
'itemView' => '_item',
], $options = ['class' => 'sorter'] ); ?>
And content of _item
<?php
use yii\helpers\Html;
?>
Treść Newsa:
<?=$model->Text;?> <br>
Autor:
<?=Yii::$app->user->identity->Name?>
<?=Yii::$app->user->identity->Surname?> <br>
Status Newsa:
<?=$model->cnNewsContentType_Id;?> <br>
<?= Html::a('Update', ['update', 'id' => $model->Id], ['class' => 'btn btn-primary']) ?>
<?= Html::a('Delete', ['delete', 'id' => $model->Id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => 'Are you sure you want to delete this item?',
'method' => 'post',
],
]) ?><br><br><br>
The News::find()->where(['urUser_Id' =>'Id'])->one() return a model not a field
then you must get the id field by the model this way
public function getUrUser($id)
{
// you already have the news model so don't need retrieve it
// it's enough pass the urUser_Id by $id
$RoyalUserData=User::findOne($id);
return $RoyalUserData->Name;
}
Then if you want show the ($RoyalUserData) Name in _item
<?=$model->getUrUser($model->urUser_Id);?>
public function getUrUser()
{
$q = News::find()->where(['urUser_Id' =>'Id'])->one();
return $q->user->name;
}
In user model you should create relation:
class News extends ActiveRecord
{
// ...
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
}
What data must be sended to dataprovider?
In my controller:
public function actionIndex() {
$searchModel = new UserSearch();
$dataProvider = $searchModel->search( Yii::$app->request->queryParams );
//other stuff and sending array of params to view
in a view:
echo ListView::widget( [
'dataProvider' => $dataProvider,
] );
but i got only id`s:
And if i`m set single view like:
'itemView' => '_single',
how send data to _single.php ?
I mean - need default template for view list items like in GridView:
GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'username',
'email:email',
'password',
'role',
//....
And then i got perfect grid:
Controller - SiteController.php
<?php
// Yii2 Listview Example : by Songwut Kanchanakosai, Thailand.
use common\models\Members;
use common\models\SearchMembers;
...
public function actionIndex() {
$searchModel = new SearchMembers();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
?>
View (1) - index.php
<?php
use yii\widgets\ListView;
...
echo ListView::widget( [
'dataProvider' => $dataProvider,
'itemView' => '_item',
] ); ?>
View (2) - _item.php
<?php
use yii\helpers\Html;
?>
<?=$model->name;?>
<?=$model->age;?>
<?=$model->mobile;?>
Example Result :
Songwut 36 +668-3949-5153
Prawee 41 +668-7323-2334
Kosol 32 +668-8014-0165
Utehn 39 +668-7874-5643
how send data to _single.php ?
Here is how, use $viewParams
$viewParams public property array $viewParams = []
Additional parameters to be passed to $itemView when it is being
rendered. This property is used only when $itemView is a string
representing a view name.
echo ListView::widget( [
'dataProvider' => $dataProvider,
'viewParams'=>['name'=>'My Name is Stefano'], //acccessed in view as $name with value 'My Name is Stefano'
] );
in official docs http://www.yiiframework.com/doc-2.0/yii-widgets-listview.html#$itemView-detail
$itemView public property
The name of the view for rendering each data item, or a callback (e.g. an anonymous function) for rendering
each data item. If it specifies a view name, the following variables
will be available in the view:
$model: mixed, the data model
$key: mixed, the key value associated with the data item
$index: integer, the zero-based index of the data item in the items array returned by $dataProvider.
$widget: ListView, this widget instance
So your User model data should be available in _single.php as $model->username
So i suppose can use Detail View in _single.php i think:
DetailView::widget([
'model' => $model,
'attributes' => [
'id',
'username',
'email:email',
//....