title: Yii2 GridView SearchModel for count of relation
body: <p>I have a model <code>item</code> that has a <code>hasMany</code> relation to an <code>image</code> model. In the item <code>GridView</code> I have a column that shows how many images that <code>item</code> has. I would like to be able to sort by this column, and possibly be able to filter with a checkbox to show only <code>item</code>s with no <code>image</code>s.</p>
  
  <p>I tried adding a check to the search model to query <code>with</code> the <code>images</code> relation, and I thought I'd add a <code>andFilterWhere</code> for where the <code>image</code> count was less than the input value. However I'm not sure the best way to have that logic, is there a better <em>Yii</em> way to filter by that count?</p>
  
  <p><strong>Update</strong>
  Following information from <a href="https://stackoverflow.com/questions/31782754/yii2-sort-a-relational-count-column-in-gridview">this question</a> I've updated my <code>item</code> model to have a method that returns the relationship count.</p>
  
  <p>I've then update my search model like this:</p>
  
  <pre><code>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()-&gt;select('item_id, COUNT(id) as image_count')-&gt;groupBy('item_id');
          $query-&gt;leftJoin(['imageCount' =&gt; $subQuery], 'imageCount.item_id = id');
  
          // add conditions that should always apply here
  
          $dataProvider = new ActiveDataProvider([
              'query' =&gt; $query,
          ]);
  
          $dataProvider-&gt;setSort([
              'attributes' =&gt; [
                  'id',
                  'product_id',
                  'manufacturer_id',
                  'scale_id',
                  'owner_id',
                  'image_count' =&gt; [
                      'asc' =&gt; ['imageCount.image_count' =&gt; SORT_ASC],
                      'desc' =&gt; ['imageCount.image_count' =&gt; SORT_DESC],
                      'label' =&gt; 'Images'
                  ]
              ]
          ]); 
  
          $this-&gt;load($params);
  
          if (!$this-&gt;validate()) {
              // uncomment the following line if you do not want to return any records when validation fails
              // $query-&gt;where('0=1');
              return $dataProvider;
          }
  
          // grid filtering conditions
          if (!empty($this-&gt;id)) {
              $query-&gt;andFilterWhere([
                  'id' =&gt; $this-&gt;id,
              ]);
          }
          if (!empty($this-&gt;product_id)) {
              $query-&gt;andFilterWhere([
                  'product_id' =&gt; $this-&gt;product_id,
              ]);
          }
          if (!empty($this-&gt;manufacturer_id)) {
              $query-&gt;andFilterWhere([
                  'manufacturer_id' =&gt; $this-&gt;manufacturer_id,
              ]);
          }
          if (!empty($this-&gt;scale_id)) {
              $query-&gt;andFilterWhere([
                  'scale_id' =&gt; $this-&gt;scale_id,
              ]);
          }
          if (!empty($this-&gt;owner_id)) {
              $query-&gt;andFilterWhere([
                  'owner_id' =&gt; $this-&gt;owner_id,
              ]);
          }
          if (!empty($this-&gt;image_count)) {
              $query-&gt;andWhere(['is','imageCount.image_count',new \yii\db\Expression('null')]);
           }
  
          $query-&gt;andFilterWhere(['like', 'sku_number', $this-&gt;sku_number])
              -&gt;andFilterWhere(['like', 'description', $this-&gt;description])
              -&gt;andFilterWhere(['like', 'details', $this-&gt;details])
              -&gt;andFilterWhere(['like', 'condition', $this-&gt;condition]);
  
          return $dataProvider;
      }
  }
  </code></pre>
  
  <p>The issue now is that the above will produce a query something like this:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>The issue being <code>items</code> that have 0 <code>image</code>s are no longer shown (and checking the box shows nothing) because the join will find nothing for that id in the <code>image</code> table</p>