Yii2 GridView SearchModel用于关系计数

时间:2018-12-12 01:12:19

标签: gridview yii2

我有一个模型itemhasMany模型有image关系。在项目GridView中,我有一列显示item有多少张图像。我希望能够按此列进行排序,并且可能能够通过一个复选框进行过滤,以仅显示item个而没有image个。

我尝试向搜索模型添加检查以查询with的{​​{1}}关系,并且我想为images的计数位置添加一个andFilterWhere小于输入值。但是我不确定具有这种逻辑的最佳方法,是否有更好的 Yii 方法可以根据该计数进行过滤?

更新 根据{{​​3}}的信息,我已经更新了image模型,使其具有一种返回关系计数的方法。

然后我像这样更新搜索模型:

item

现在的问题是,上面的内容将产生类似以下的查询:

class ItemSearch extends Item
{
    public $image_count;

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['id', 'product_id', 'manufacturer_id', 'scale_id', 'owner_id', 'quantity'], 'integer'],
            [['sku_number', 'description', 'details', 'condition'], 'safe'],
            [['price', 'sale_price', 'image_count'], 'number'],
        ];
    }

    /**
     * @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 = Item::find();
        $subQuery = Image::find()->select('item_id, COUNT(id) as image_count')->groupBy('item_id');
        $query->leftJoin(['imageCount' => $subQuery], 'imageCount.item_id = id');

        // add conditions that should always apply here

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);

        $dataProvider->setSort([
            'attributes' => [
                'id',
                'product_id',
                'manufacturer_id',
                'scale_id',
                'owner_id',
                'image_count' => [
                    'asc' => ['imageCount.image_count' => SORT_ASC],
                    'desc' => ['imageCount.image_count' => SORT_DESC],
                    'label' => 'Images'
                ]
            ]
        ]); 

        $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;
        }

        // grid filtering conditions
        if (!empty($this->id)) {
            $query->andFilterWhere([
                'id' => $this->id,
            ]);
        }
        if (!empty($this->product_id)) {
            $query->andFilterWhere([
                'product_id' => $this->product_id,
            ]);
        }
        if (!empty($this->manufacturer_id)) {
            $query->andFilterWhere([
                'manufacturer_id' => $this->manufacturer_id,
            ]);
        }
        if (!empty($this->scale_id)) {
            $query->andFilterWhere([
                'scale_id' => $this->scale_id,
            ]);
        }
        if (!empty($this->owner_id)) {
            $query->andFilterWhere([
                'owner_id' => $this->owner_id,
            ]);
        }
        if (!empty($this->image_count)) {
            $query->andWhere(['is','imageCount.image_count',new \yii\db\Expression('null')]);
         }

        $query->andFilterWhere(['like', 'sku_number', $this->sku_number])
            ->andFilterWhere(['like', 'description', $this->description])
            ->andFilterWhere(['like', 'details', $this->details])
            ->andFilterWhere(['like', 'condition', $this->condition]);

        return $dataProvider;
    }
}

由于SELECT `item`.* FROM `item` LEFT JOIN (SELECT `item_id`, COUNT(id) as image_count FROM `image` GROUP BY `item_id`) `imageCount` ON imageCount.item_id = id WHERE `imageCount`.`image_count`=0 具有0个items的问题将不再显示(并且选中该框不会显示任何内容),因为联接在image表中找不到该ID的任何内容< / p>

2 个答案:

答案 0 :(得分:3)

您应检查WHERE imageCount.image_count IS NULL而不是WHERE imageCount.image_count=0,因为那些没有任何相关图像的行将在null下显示为image_count,并更改条件来自

$query->andFilterWhere(['imageCount.image_count' => 0]); 

$query->andWhere(['is','imageCount.image_count',new \yii\db\Expression('null')]);`

您的查询应生成为

SELECT `item`.* FROM `item` 
LEFT JOIN
(
   SELECT `item_id`, COUNT(id) as image_count 
   FROM `image` 
   GROUP BY `item_id`
) `imageCount` 

ON imageCount.item_id = id 

WHERE `imageCount`.`image_count` is NULL

更新

由于您仍然面临问题,所以我认为我有空闲时间来发现此问题,因此我提出了以下建议

在过滤图像计数为0的项目时遇到问题,但我没有确切的架构,但在下面的示例中,我将使用Shoots和联结表ShootTag模型中它们的相关标签

  • Shoots

下面是模式和数据的示例

+----+------------+--------+------------+
| id | name       | active | shoot_type |
+----+------------+--------+------------+
|  1 | aslam omer |      1 | modeling   |
|  2 | asif       |      1 | modeling   |
|  3 | saleem     |      1 | modeling   |
|  4 | sajid      |      1 | modeling   |
|  5 | tasleem    |      1 | modeling   |
|  6 | tehseen    |      1 | modeling   |
|  7 | amjad      |      1 | modeling   |
|  8 | shaban     |      1 | modeling   |
|  9 | irfan      |      1 | modeling   |
+----+------------+--------+------------+
  • ShootTags

下面是模式和数据的示例

+----------+--------+
| shoot_id | tag_id |
+----------+--------+
|        1 |      1 |
|        1 |      2 |
|        1 |      3 |
|        1 |      4 |
|        2 |      1 |
|        2 |      2 |
|        2 |      3 |
|        3 |      1 |
|        4 |      1 |
|        4 |      4 |
+----------+--------+

现在考虑上述表格和数据,我有一个名称为ShootsSearch的搜索模型,该模型用于显示所有芽,并且我想针对{内保存的每个芽显示标签的数量{1}}模型。

我没有添加GridView的代码,因为它无关紧要,我的搜索模型ShootTag具有以下搜索方法,该方法可以正确地对芽标签模型中的芽进行计数。

  • 与您的代码不同的是,我在第一个查询中使用ShootsSearch模型,而不是在使用ShootsSearch时应使用Shoots模型,{

  • 在搜索模型中声明了{1}}作为您使用的Item::find();的别名
  • 然后在主查询中的行ItemSearch::find();上需要将空值显示为0,以便可以在此处使用条件选择。

  • 然后,您需要检查image_count以应用new Expression('if(st.totalTags is NOT NULL,st.totalTags,0) as totalTags'),因为if ($this->totalTags == '0') {的实际值为$query->andWhere(['IS', 'totalTags', new Expression('null')]);,其中没有针对任何{ {1}},在其他部分,您将使用null

这在您希望看到下面的图像的所有三种情况下都能正常工作

首次使用默认视图

enter image description here

搜索总标签数为4的芽

enter image description here

搜索TotalTags计数为0的芽

enter image description here

您应在代码中替换以下内容

  • totalTagsShoot
  • query->andFilterWhere(['=', 'totalTags', $this->totalTags]);public $totalTags
  • public $image_countShootTags
  • Imageshoot_id / item_id

这是搜索模型,代码已通过测试并且可以正常工作。

ShootsSearch

答案 1 :(得分:1)

我的理解是,您需要计算关联表中的数据量,并根据统计信息进行排序和过滤。

然后您的ItemSearch::search()方法应该可以更改为此:

public function search($params)
{
    $query = Item::find()->select('*, (select count(*) from image where image.item_id = item.id) as image_count'); // If the table name of your Image table is image, if the table name of your Item table is item

    // add conditions that should always apply here

    $dataProvider = new ActiveDataProvider([
        'query' => $query,
    ]);

    $dataProvider->setSort([
        'attributes' => [
            'id',
            'product_id',
            'manufacturer_id',
            'scale_id',
            'owner_id',
            'image_count'
        ]
    ]); 

    $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;
    }

    // grid filtering conditions
    if (!empty($this->id)) {
        $query->andFilterWhere([
            'id' => $this->id,
        ]);
    }
    if (!empty($this->product_id)) {
        $query->andFilterWhere([
            'product_id' => $this->product_id,
        ]);
    }
    if (!empty($this->manufacturer_id)) {
        $query->andFilterWhere([
            'manufacturer_id' => $this->manufacturer_id,
        ]);
    }
    if (!empty($this->scale_id)) {
        $query->andFilterWhere([
            'scale_id' => $this->scale_id,
        ]);
    }
    if (!empty($this->owner_id)) {
        $query->andFilterWhere([
            'owner_id' => $this->owner_id,
        ]);
    }
    if (!empty($this->image_count)) {
        $query->andWhere([
            'image_count' => $this->image_count,
        ]);
     }

    $query->andFilterWhere(['like', 'sku_number', $this->sku_number])
        ->andFilterWhere(['like', 'description', $this->description])
        ->andFilterWhere(['like', 'details', $this->details])
        ->andFilterWhere(['like', 'condition', $this->condition]);

    return $dataProvider;
}

但是,如果您的image_count通常需要计算和统计信息,并且您的数据量很大,那么建议您将此字段重新定义为项目表。

更新:

我的错,聚合字段无法通过where条件过滤,但是您可以使用具有以下条件的

$query->andFilterHaving([
    'image_count' => $this->image_count,
]);