How do I enable my Query button in my view? - php

I add another table field in my view , but the search button disappeared , How can I retrieve this form button ?
SaleItems = And a table mysql database.
<?php
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'formatter' => ['class' => 'yii\i18n\Formatter','nullDisplay' => ''],
'columns' => [
['class' => 'yii\grid\SerialColumn'],
**[
'attribute' => 'Data',
'content' => function(SaleItems $model, $key, $index, $column) {
return date('d/m/Y', strtotime($model->sale->date));
},
'header' => 'DATA'
],**
]); ?>
</div>

The search field disappears because in not setted properly in searchModel ..
for this you must extend the related modelSeacrh adding the relation with the related model and the filter for the field you need ..
for this you must set in the base mode, the relation
public function getSale()
{
return $this->hasOne(Sale::className(), ['id' => 'sale_id']);
}
/* Getter for sale data */
public function getSaleData() {
return $this->sale->data;
}
then setting up the search model declaring
/* your calculated attribute */
public $date;
/* setup rules */
public function rules() {
return [
/* your other rules */
[['data'], 'safe']
];
}
and extending
public function search($params) {
adding proper sort, for data
$dataProvider->setSort([
'attributes' => [
.....
'data' => [
'asc' => ['tbl_sale.data' => SORT_ASC],
'desc' => ['tbl_sale.data' => SORT_DESC],
'label' => 'Data'
]
]
]);
proper relation
if (!($this->load($params) && $this->validate())) {
/**
* The following line will allow eager loading with country data
* to enable sorting by country on initial loading of the grid.
*/
$query->joinWith(['sale']);
return $dataProvider;
}
and proper filter condition
// filter by sale data
$query->joinWith(['sale' => function ($q) {
$q->where('sale.data = ' . $this->data . ' ');
}]);
Once you do al this the searchModel contain the information for filter and the search field is showed in gridview
What in this answer is just a list of suggestion
you can find detailed tutorial in this doc (see the scenario 2 and adapt to your need)
http://www.yiiframework.com/wiki/621/filter-sort-by-calculated-related-fields-in-gridview-yii-2-0/

Related

How to integrate SQL-Generated columns in Yii2 GridView

To show my GridView I use this ActiveDataProvider:
public function search($params)
{
$query = PublicationsPublication::find()
->select(['eid', 'title', 'pubdate', 'citedby', "STRING_AGG(DISTINCT(CONCAT(author.authid, ' - ', authname)), ', ') AS authors"])
->joinWith('publicationsAuthor')
->groupBy(['eid','title','pubdate','citedby']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
...
}
I can't figure out how to use the column generated by the STRING_AGG() function in the Gridview.
Just in case is needed, the publicationsAuthor relation is coded this way:
public function getPublicationsAuthor() {
return $this->hasMany(PublicationsAuthor::className(), ['authid' => 'authid'])
->viaTable('publications.pub_author', ['pubid' => 'id']);
}
I need to use the STRING_AGG() function because I want to show many authors in one cell of the Gridview.
I tried to use the "authors" column in this way:
$gridColumns = [
[
'class' => 'kartik\grid\SerialColumn',
'width' => '20px',
],
'eid',
'title',
'pubdate',
'citedby',
'authors',
];
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => $gridColumns,
'pager' => [
'firstPageLabel' => 'First',
'lastPageLabel' => 'Last'
],
...
]);
But unfortunately it didn't work. In the Grid all the values are set to "not set". The query works great because I tested it in PgAdmin.
yii\data\ActiveDataProvider works with models so only fields defined by model are available by default. The easiest way to add field generated by some expression is to add public property with same name to your model like this:
class PublicationsPublication extends ActiveRecord
{
public $authors;
// ... other code in PublicationsPublication model ...
public function attributeLabels()
{
// You can also add label for new field
return [
'authors' => 'Authors',
// ... other labels ...
];
}
}
The public property $authors will be loaded with data from field authors in the result of your SQL query. Then you can use it in grid as any other field.
The other option is to use yii\data\SqlDataProvider instead of yii\data\ActiveDataProvider.

How to multiply two columns in yii2 grid view

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;

Yii2 get data from many to many relation in gridview and apply filter

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.

Sorting calculated fields in Yii2 (Grid View)

i am need to sort some fields (asc,desc) in GridView, but same fields are calculated. Look at code below:
SearchModel:
class ObjectSearch extends Object {
use SearchModelTrait;
public function rules()
{
return [
['id', 'integer', 'min' => 1],
];
}
public function search($params)
{
$this->company_id = \Yii::$app->user->identity->companyId;
$query = Object::find()->where(['company_id' => $this->company_id]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
]);
$dataProvider->setSort([
'attributes' => [
'id',
'name',
'lastReportResult' => [
'asc' => ['lastReportResult' =>SORT_ASC ],
'desc' => ['lastReportResult' => SORT_DESC],
'default' => SORT_ASC
],
'reportPercentDiff'
]
]);
if (!($this->load($params,'ObjectSearch') && $this->validate())) {
return $dataProvider;
}
$this->addCondition($query, 'id');
return $dataProvider;
}
Methods in Object model:
public function getLastReportResult()
{
$lastReport = $this->getLastReport();
$message = 0;
if (!empty($lastReport)) {
$statistic = new ReportStatistic($lastReport);
$message = $statistic->getPercent();
}
return $message;
}
/**
* #return int
*/
public function getReportPercentDiff()
{
$lastReport = $this->getLastReport();
$message = 0;
if (!empty($lastReport)) {
$statistic = $lastReport->getReportDiff();
if (!empty($statistic['diff'])) {
$message = $statistic['diff']['right_answers_percent_diff'];
} elseif (!empty($statistic['message'])) {
$message = $statistic['message'];
}
}
return $message;
}
So, by this methods, i am calculating a values of two fields, which are need's sorting. This way doesn't working, i have a Database Exception, because object table hasn't this fields. exception
How to do sorting of this fields ?
Update: I am the author of this answer and this answer is not accurate. Preferred way is to use database view
Add two public properties to ObjectSearch.php and mark it as safe
class ObjectSearch extends Object {
use SearchModelTrait;
public $lastReportResult, $reportPercentDiff;
public function rules()
{
return [
['id', 'integer', 'min' => 1],
[['lastReportResult', 'reportPercentDiff'], 'safe']
];
}
public function search($params)
{
$this->company_id = \Yii::$app->user->identity->companyId;
$query = Object::find()->where(['company_id' => $this->company_id]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
]);
$dataProvider->setSort([
'attributes' => [
'id',
'name',
'lastReportResult' => [
'asc' => ['lastReportResult' =>SORT_ASC ],
'desc' => ['lastReportResult' => SORT_DESC],
'default' => SORT_ASC
],
'reportPercentDiff' => [
'asc' => ['reportPercentDiff' =>SORT_ASC ],
'desc' => ['reportPercentDiff' => SORT_DESC],
'default' => SORT_ASC
],
]
]);
if (!($this->load($params,'ObjectSearch') && $this->validate())) {
return $dataProvider;
}
$this->addCondition($query, 'id');
return $dataProvider;
}
Then in index.php (view file in which you are having grid view) add lastReportResult and reportPercentDiff in array of all attributes (list of all attributes ob Object model)
...
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
// your other attribute here
'lastReportResult',
'reportPercentDiff',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
...
For more info you can visit Kartik's blog at Yii
Though this is an old thread, stumbled upon this and tried to find other method to achieve sorting of purely calculated field to no avail... and this post unfortunately is not an answer as well... It just that I feel the need to post it here to give a heads up to those that still looking for the solution so as not to scratch their heads when trying the solution given and still fail.
The given example from documentation or referred links as far as I have tested only works if you have a column within the database schema (whether in the main table or the related tables). It will not work if the virtual attribute/calculated field you create is based on calculating (as an example multiplication of 2 column on the table)
e.g:
table purchase: | purchase_id | product_id | quantity |
table product: | product_id | unit_price |
then, if we use a virtual attribute 'purchase_total' for model 'purchase' which is the multiplication of quantity and unit_price (from the join table of purchase and product on product_id), eventually you will hit an error saying 'purchase_total' column can not be found when you tried to sort them using the method discussed so far.

PHP, Yii2 GridView filtering on relational value

Following on from this:
Yii2 how does search() in SearchModel work?
I would like to be able to filter a GridView column of relational data. This is what I mean:
I have two tables, TableA and TableB. Both have corresponding models generated using Gii. TableA has a foreign key to a value in TableB, like this:
TableA
attrA1, attrA2, attrA3, TableB.attrB1
TableB
attrB1, attrB2, attrB3
attrA1 and attrB1 are the primary keys of their corresponding tables.
Now, I have a Yii2 GridView of attrA2, attrA3 and attrB2. I have a working filter on attrA2 and attrA3 so that I can search on column values. I also have a working sort for these two columns too - by just clicking on the column header. I would like to be able to add this filtering and sorting on attrB2 too.
My TableASearch model looks like this:
public function search($params){
$query = TableA::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$this->addCondition($query, 'attrA2');
$this->addCondition($query, 'attrA2', true);
$this->addCondition($query, 'attrA3');
$this->addCondition($query, 'attrA3', true);
return $dataProvider;
}
In my TableA model, I set the related value like this
public $relationalValue;
public function afterFind(){
$b = TableB::find(['attrB1' => $this->attrB1]);
$this->relationalValue = $b->relationalValue;
}
Although it is probably not the best way of doing this. I think I have to use $relationalValue somewhere in my search function but I'm not sure how. Similarly, I would like to be able to sort by this column too - just like I can for attrA2 and AttrA3 by clicking on the header link`. Any help would be appreciated. Thanks.
This is based on the description in the guide. The base code for the SearchModel comes from the Gii code generator. This is also assuming that $this->TableB has been setup using hasOne() or hasMany() relation. See this doc.
1. Setup search model
In TableASearch model add:
public function attributes()
{
// add related fields to searchable attributes
return array_merge(parent::attributes(), ['TableB.attrB1']);
}
public function rules()
{
return [
/* your other rules */
[['TableB.attrB1'], 'safe']
];
}
Then in TableASearch->search() add (before $this->load()):
$dataProvider->sort->attributes['TableB.attrB1'] = [
'asc' => ['TableB.attrB1' => SORT_ASC],
'desc' => ['TableB.attrB1' => SORT_DESC],
];
$query->joinWith(['TableB']);
Then the actual search of your data (below $this->load()):
$query->andFilterWhere([
'like',
'TableB.attrB1',
$this->getAttribute('TableB.attrB1')
]);
2. Configure GridView
Add to your view:
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
/* Other columns */
'TableB1.attrB1',
/* Other columns */
]
]);
Filtering a gridview by a column is damn easy in Yii 2.0. Please add the filter attribute to a gridview column having lookup values, as under:
[
"class" => yii\grid\DataColumn::className(),
"attribute" => "status_id",
'filter' => ArrayHelper::map(Status::find()->orderBy('name')->asArray()->all(), 'id', 'name'),
"value" => function($model){
if ($rel = $model->getStatus()->one()) {
return yii\helpers\Html::a($rel->name,["crud/status/view", 'id' => $rel->id,],["data-pjax"=>0]);
} else {
return '';
}
},
"format" => "raw",
],
I'm stuck with this problem too, and my solution is rather different. I have two simple models:
Book:
class Book extends ActiveRecord
{
....
public static function tableName()
{
return 'books';
}
public function getAuthor()
{
return $this->hasOne(Author::className(), ['id' => 'author_id']);
}
And Author:
class Author extends ActiveRecord
{
public static function tableName()
{
return 'authors';
}
public function getBooks()
{
return $this->hasMany(Book::className(), ['author_id' => 'id']);
}
But my search logic is in different model. And i didn't find how can i implement search without creating additional field author_first_name. So this is my solution:
class BookSearch extends Model
{
public $id;
public $title;
public $author_first_name;
public function rules()
{
return [
[['id', 'author_id'], 'integer'],
[['title', 'author_first_name'], 'safe'],
];
}
public function search($params)
{
$query = Book::find()->joinWith(['author' => function($query) { $query->from(['author' => 'authors']);}]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => array('pageSize' => 50),
'sort'=>[
'attributes'=>[
'author_first_name'=>[
'asc' => ['author.first_name' => SORT_ASC],
'desc' => ['author.first_name' => SORT_DESC],
]
]
]
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
....
$query->andWhere(['like', 'author.first_name', $this->author_first_name]);
return $dataProvider;
}
}
This is for creating table alias: function($query) { $query->from(['author' => 'authors']);}
And GridView code is:
<?php echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
[
'attribute' => 'id',
'filter' => false,
],
[
'attribute' => 'title',
],
[
'attribute' => 'author_first_name',
'value' => function ($model) {
if ($model->author) {
$model->author->getFullName();
} else {
return '';
}
},
'filter' => true,
],
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
I will appreciate any critiques and advice.

Categories