[英]Yii2: sort a relational count column in GridView
[EDITED 2] [编辑2]
I'm having hard time to sort by the 'topicCount' which is defined as a relational getter on a model 'Tag'. 我很难按'topicCount'进行排序,'topicCount'被定义为模型'Tag'上的关系获取器。 A Topic can have a lots of Tag, and wish to sort the Tags by how many Topics containing that Tag.
一个主题可以有很多标签,并希望按照包含该标签的主题数对标签进行排序。
In my models/Tag.php: 在我的模型/Tag.php中:
public function getTopicCount()
{
return TopicTag::find()->where(['tag_id' => $this->id])->count();
}
And in my views/tag/index.php: 在我的观点/ tag / index.php中:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'id',
'name',
[
'attribute'=>'topicCount',
'value' => 'topicCount',
],
'created_at',
['class' => 'yii\grid\ActionColumn','template' => '{view}',],
],
]); ?>
And in my controllers/TagController.php: 在我的controllers / TagController.php中:
public function actionIndex()
{
$dataProvider = new ActiveDataProvider([
'query' => Tag::find(),
'sort'=> [
'defaultOrder' => ['id'=>SORT_DESC],
'attributes' => ['id','topicCount'],
],
'pagination' => [
'pageSize' => 100,
],
]);
return $this->render('index', [
'dataProvider' => $dataProvider,
]);
}
And in my models/TagSearch.php: 在我的模型/TagSearch.php中:
<?php
namespace common\models;
use Yii;
/**
* This is the model class for table "tags".
*
* @property integer $id
* @property string $name
* @property string $created_at
* @property string $updated_at
*/
class TagSearch extends Tag
{
public $topicCount;
/**
* @inheritdoc
*/
public function rules()
{
return [
[['topicCount'], 'safe']
];
}
public function search($params)
{
// create ActiveQuery
$query = Tag::find();
$query->joinWith(['topicCount']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$dataProvider->sort->attributes['topicCount'] = [
'asc' => ['topicCount' => SORT_ASC],
'desc' => ['topicCount' => SORT_DESC],
];
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->andFilterWhere([
//... other searched attributes here
])
->andFilterWhere(['=', 'topicCount', $this->topicCount]);
return $dataProvider;
}
}
And in the index view I can see the correct topicCount: 在索引视图中,我可以看到正确的topicCount:
but on clicking the topicCount column I get the error: 但是在单击topicCount列时出现错误:
exception 'PDOException' with message 'SQLSTATE[42703]: Undefined column: 7 ERROR: column "topicCount" does not exist LINE 1: SELECT * FROM "tags" ORDER BY "topicCount" LIMIT 100
Thanks for any guidance..! 感谢您的指导。
Following Lucas' advice, I've set my dataProvider query in my $dataProvider like this: 遵循卢卡斯的建议,我在$ dataProvider中设置了dataProvider查询,如下所示:
'query' => $query->select(['tags.*','(select count(topic_tags.id) from topic_tags where topic_tags.tag_id=tags.id) topicCount'])->groupBy('tags.id'),
and I got error: 我得到了错误:
exception 'PDOException' with message 'SQLSTATE[42P01]: Undefined table: 7 ERROR: missing FROM-clause entry for table "tags"
so I reformulated like this: 所以我这样改写:
'query' => $query->from('tags')->leftJoin('topic_tags','topic_tags.tag_id = tags.id')->select(['tags.*','(select count(topic_tags.id) from topic_tags where topic_tags.tag_id=tags.id) topicCount'])->groupBy('tags.id'),
and now I get the result: 现在我得到结果:
apparently the topicCount column is not set, so when I try to sort by it, it returns the error: 显然没有设置topicCount列,因此当我尝试按其排序时,它返回错误:
exception 'PDOException' with message 'SQLSTATE[42703]: Undefined column: 7 ERROR: column "topicCount" does not exist
but when I try the SQL directly on the DB, it works fine: 但是当我直接在数据库上尝试SQL时,它可以正常工作:
so I suppose the problem is in the way Yii handles the alias 'topicCount'? 所以我想问题出在Yii处理别名'topicCount'的方式上吗?
Still the same result without the topicCount set in the Grid view. 没有在Grid视图中设置topicCount的结果仍然相同。 I show my TagSearch model, TagController and views/tag/index view file below:
我在下面显示我的TagSearch模型,TagController和views / tag / index视图文件:
TagSearch
标签搜索
<?php
namespace common\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use common\models\Tag;
/**
* TagSearch represents the model behind the search form about `common\models\Tag`.
*/
class TagSearch extends Tag
{
public $topicCount;
/**
* @inheritdoc
*/
public function rules()
{
return [
[['id', 'topicCount'], 'integer'],
[['name', 'created_at', 'updated_at', 'topicCount'], '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 = Tag::find();
$dataProvider = new ActiveDataProvider([
'query' => $query->from("tags")->select(["tags.*","(select count(topic_tags.id) from topic_tags where topic_tags.tag_id=tags.id) topicCount"])->groupBy("tags.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;
}
$query->andFilterWhere([
'id' => $this->id,
'topicCount' => $this->topicCount,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
]);
$query->andFilterWhere(['like', 'name', $this->name]);
return $dataProvider;
}
}
Tag model
标签模型
<?php
namespace common\models;
use Yii;
/**
* This is the model class for table "tags".
*
* @property integer $id
* @property integer $topicCount
* @property string $name
* @property string $created_at
* @property string $updated_at
*/
class Tag extends \yii\db\ActiveRecord
{
public $topicCount;
/**
* @inheritdoc
*/
public static function tableName()
{
return 'tags';
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[['topicCount'], 'integer'],
[['name'], 'string'],
[['created_at', 'updated_at'], 'required'],
[['created_at', 'updated_at'], 'safe']
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
'topicCount' => 'TC',
'created_at' => 'Created At',
'updated_at' => 'Updated At',
];
}
}
TagController
标签控制器
public function actionIndex()
{
$searchModel = new TagSearch();
$myModels = $searchModel->search([]);
return $this->render('index', [
'dataProvider' => $myModels,
]);
}
tags/index
标签/索引
<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
'id',
'name',
'topicCount',
'created_at',
'updated_at',
['class' => 'yii\grid\ActionColumn','template' => '{view}',],
],
]); ?>
What am I missing? 我想念什么?
So resolved following this wiki : 所以解决了这个维基 :
Since in my case I don't use SUM('amount'), I changed to the following and works perfectly: 由于在我的情况下,我不使用SUM('amount'),因此我将其更改为以下内容并可以完美地工作:
Tag model: 标签型号:
public function getTopicCount()
{
return $this->hasMany(TopicTag::className(), ["tag_id" => "id"])->count();
}
TagSearch model: TagSearch模型:
$query = Tag::find();
$subQuery = TopicTag::find()->select('tag_id, COUNT(tag_id) as topic_count')->groupBy('tag_id');
$query->leftJoin(["topicSum" => $subQuery], '"topicSum".tag_id = id');
Just encountered a problem with the generated SQL: 刚遇到生成的SQL问题:
exception 'PDOException' with message 'SQLSTATE[42P01]: Undefined table: 7 ERROR: missing FROM-clause entry for table "topicsum"
This might be a Postgres-specific issue, had to arrange the code so that the generated SQL becomes like this: 这可能是特定于Postgres的问题,必须安排代码以使生成的SQL变为:
SELECT COUNT(*) FROM "tags"
LEFT JOIN (SELECT "tag_id", COUNT(*) as topic_count FROM "topic_tags" GROUP BY "tag_id") "topicSum"
ON "topicSum".tag_id = id
note the double-quotation in "topicSum".tag_id
part. 请注意
"topicSum".tag_id
部分中的双引号。
Hope this might be of help for someone using Postgres on Yii2. 希望这对在Yii2上使用Postgres的人有所帮助。
You should alter your query to group and select the count instead of working with relations. 您应该将查询更改为分组并选择计数,而不是使用关系。
$query->groupBy('tags.id')->select(['tags.*','(select count(topic_tag.id) from topic_tag where topic_tag.tag.id=tags.id) topicCount']);
This will add topicCount
as a result object in your query, which will make it behave like an ordinary column. 这会将
topicCount
添加为查询中的结果对象,这将使其行为像普通列一样。
Also as a side note, for a method to act a relation in Yii2, it must return an ActiveQuery
object. 另外,对于在Yii2中执行关系的方法,它必须返回
ActiveQuery
对象。 Your getTopicCount()
is returning the count as an int, instead of the query, therefore Yii2 will not treat it like a relation. 您的
getTopicCount()
会将计数返回为int而不是查询,因此Yii2不会将其视为关系。
Based on this Wiki and @arogachev's answer. 基于此Wiki和@arogachev的答案。 I put
select
property to get tags count 我放了
select
属性来获取标签计数
public function search($params)
{
$query = SomeModels::find()
->select('subQueryName.field_count, someModels.*');
// ....
so it will give SQL like this SELECT subQuery.field_count, someModels.*
... 因此它将像这样的SQL给
SELECT subQuery.field_count, someModels.*
...
at view (grid), 在视图(网格)上,
[
'attribute'=> 'field_count',
],
Thank you @arogachev , you saved me :) 谢谢@arogachev,您救了我:)
light solution is just reate view
in PostgreSQL 解决方案只是PostgreSQL中的
view
and generate model via gii
generator using as model and order & find work. 并通过
gii
生成器生成模型并用作模型并订购和查找工作。
For update & delete use table
model for search & index use view
model. 对于更新和删除,使用
table
模型进行搜索和索引,使用view
模型。
For example 例如
for actions update
& delete
use Tag
model 动作
update
和delete
使用Tag
模型
for actions index
& view
use TagView
model. 对于动作
index
和view
使用TagView
模型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.