Yii2: Sortiere eine relationale Zählerspalte in GridView

[EDITED 2]

Es fällt mir schwer, nach dem 'topicCount' zu sortieren, der als relationaler Getter auf einem Modell 'Tag' definiert ist. Ein Thema kann viele Tags enthalten und möchte die Tags nach der Anzahl der Themen sortieren, die dieses Tag enthalten.

In meinen Modellen / Tag.php:

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

Und in meiner views / tag / index.php:

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

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

Und in meiner controller / 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,
    ]);
}

Und in meinen Modellen / 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;
}


}

Und in der Indexansicht kann ich das richtige TopicCount sehen:

Aber beim Klicken auf die TopicCount-Spalte erhalte ich den Fehler:

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

Vielen Dank für jede Anleitung ..!

[BEARBEITEN

Folgend dem Rat von Lucas habe ich meine dataProvider-Abfrage in meinem $ dataProvider wie folgt festgelegt:

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

und ich habe Fehler:

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

so habe ich so umformuliert:

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

und jetzt bekomme ich das Ergebnis:

Anscheinend ist die topicCount-Spalte nicht festgelegt. Wenn ich also versuche, danach zu sortieren, wird der Fehler zurückgegeben:

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

aber wenn ich die SQL direkt auf der DB versuche, funktioniert es gut:

so ich nehme an, das Problem liegt in der Art und Weise, wie Yii den Alias 'topicCount' behandelt?

2nd EDIT

Noch immer das gleiche Ergebnis ohne den in der Rasteransicht festgelegten TopicCount. Ich zeige mein TagSearch-Modell, TagController und die Datei views / tag / index view unten an:

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

Was vermisse ich

Antworten auf die Frage(8)

Ihre Antwort auf die Frage