2015-08-03 2 views
3

[EDITED 2]Yii2: сортировать реляционное Количество столбцов в GridView

У меня трудное время для сортировки по «topicCount», который определяется как реляционный геттер на модель «Tag». Тема может иметь много тегов и хочет сортировать теги по количеству тем, содержащих этот тег.

В моей модели/Tag.php:

public function getTopicCount() 
{ 
    return TopicTag::find()->where(['tag_id' => $this->id])->count(); 
} 

И в моих взглядах/теги/index.php:

<?= GridView::widget([ 
    'dataProvider' => $dataProvider, 
    'columns' => [ 
     'id', 
     'name', 
     [ 
      'attribute'=>'topicCount', 
      'value' => 'topicCount', 
     ], 
     'created_at', 

     ['class' => 'yii\grid\ActionColumn','template' => '{view}',], 
    ], 
]); ?> 

И в моих контроллерах/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, 
    ]); 
} 

И в моих моделях/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; 
} 


} 

И в индексном я могу увидеть правильный topicCount:

enter image description here

но нажав на колонку 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

Спасибо за какие-либо указания. .!


[EDIT]

Следуя совету Лукаса, я установил свой 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'), 

и я получил ошибку:

exception 'PDOException' with message 'SQLSTATE[42P01]: Undefined table: 7 ERROR: missing FROM-clause entry for table "tags"

поэтому я переформулировал следующим образом:

 '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'), 

и теперь я получаю результат:

enter image description here

по-видимому, столбец topicCount не установлен, поэтому, когда я пытаюсь сортировать его, он возвращает ошибку:

exception 'PDOException' with message 'SQLSTATE[42703]: Undefined column: 7 ERROR: column "topicCount" does not exist

, но когда я пытаюсь использовать SQL непосредственно в БД, он отлично работает:

enter image description here

поэтому я полагаю, что проблема в том, как Yii обрабатывает псевдоним «topicCount»?


второй EDIT

Все тот же результат без topicCount установлен в виде таблицы. я показываю свою модель TagSearch, TagController и мнения/теги/представление индекса файла ниже:

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 модель

<?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, 
    ]); 
} 

теги/индекс

<?= GridView::widget([ 
    'dataProvider' => $dataProvider, 
    'columns' => [ 
     'id', 
     'name', 
     'topicCount', 
     'created_at', 
     'updated_at', 
     ['class' => 'yii\grid\ActionColumn','template' => '{view}',], 
    ], 
]); ?> 

Что мне не хватает?

+0

У вас есть тема Столбец в таблице тегов? Что такое topicCount? – mohit

+0

привет mohit спасибо! no topicCount не является столбцом в таблице тегов, я хочу получить его через отношение, как в: public function getTopicCount() { return TopicTag :: find() -> где (['tag_id' => $ this-> id ]) -> счетчик(); } – dcc

+0

Я решил это, добавив столбец в список выбора. В моем случае функция геттера отсутствовала в модели, которую я не рассматривал. Я думал, что Yii будет рассматривать результаты запроса и использовать эти поля в качестве столбцов. Если у вас есть функция getter в модели и вычисление в SQL как именованное поле, то, похоже, она работает. Это немного лишнее. – Chloe

ответ

3

Так решены следующие this wiki:

Так как в моем случае, если я не использую SUM ('количество'), я изменил к следующему и отлично работает:

Tag модель:

public function getTopicCount() 
{ 
    return $this->hasMany(TopicTag::className(), ["tag_id" => "id"])->count(); 

} 

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'); 

Просто столкнулся с проблемой с го е генерироваться SQL:

exception 'PDOException' with message 'SQLSTATE[42P01]: Undefined table: 7 ERROR: missing FROM-clause entry for table "topicsum" 

Это может быть 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 

примечание двойной кавычки в "topicSum".tag_id части.

Надеюсь, это может помочь кому-то, кто использует Postgres на Yii2.

1

Вы должны изменить свой запрос, чтобы группировать и выбирать счетчик вместо работы с отношениями.

$query->groupBy('tags.id')->select(['tags.*','(select count(topic_tag.id) from topic_tag where topic_tag.tag.id=tags.id) topicCount']); 

Это добавит topicCount в качестве объекта результата в запросе, который сделает его вести себя как обычный столбец.

Также как побочный документ, для способа действия отношения в Yii2 он должен вернуть объект ActiveQuery. Ваш getTopicCount() возвращает счетчик как int вместо запроса, поэтому Yii2 не будет рассматривать его как отношение.

+0

спасибо, Лукас, я попробовал вам предложение и снова застрял. Не могли бы вы взглянуть на мое редактирование? Благодаря! – dcc

+0

Вам не нужно добавлять a() или join(), поскольку мы используем подзапрос, а не соединение. Также я забываю упомянуть, что вам нужно будет добавить поле «public $ topicCount»; для вашего тега класса модели, чтобы где-то было сохранено значение. Пожалуйста, постарайтесь добавить дополнения groupBy() и select(), которые я дал вам в нижней части поиска() – lucas

+0

, спасибо за возвращение. Я пробовал ваше предложение, но все равно не повезло. О дополнительных возможностях from(), возможно, потому, что я использую Postgres, он возвращает ошибку, если я не помещаю ее в $ query. Я снова редактировал свой вопрос с помощью упрощенного набора файлов. Я ценю, если вы можете показать мне свет к выходу ... – dcc

0

На основании this Wiki и ответа @ arogachev. Я ставлю select свойство, чтобы получить теги подсчитывать

public function search($params) 
{ 
$query = SomeModels::find() 
     ->select('subQueryName.field_count, someModels.*'); 
// .... 

так это даст SQL как этот SELECT subQuery.field_count, someModels.* ...

в целях (сетки),

[ 
    'attribute'=> 'field_count', 
], 

Спасибо @arogachev, вы спасли меня :)

0

решение свет только reate view в PostgreSQL

и генерировать модель с помощью gii генератора с использованием как модель и заказ & найти работу.

Для обновления & удалять использование table модель для поиска & использование view модель.

Например

для действий update & delete использование Tag модели

за действия index & view использования TagView модели.

Смежные вопросы