Search code examples
phpyiiyii-extensionsyii-components

yii CGridView filter with relations


I'm using yii for my web application. In one of my view I have CGridView and dataprovider is Mail model. In this model I have relation with with 3 other models. In the grid I show cols from three models. How can I filter the CGridView?

UPDATE:

<?php $dialog = $this->widget('ext.ecolumns.EColumnsDialog', array(
           'options'=>array(
                'title' => 'Layout settings',
                'autoOpen' => false,
                'show' =>  'fade',
                'hide' =>  'fade',
            ),
           'htmlOptions' => array('style' => 'display: none'), //disable flush of dialog content
           'ecolumns' => array(
                'gridId' => 'mails-grid', //id of related grid
                'storage' => 'session',  //where to store settings: 'db', 'session', 'cookie'
                'fixedLeft' => array('CCheckBoxColumn'), //fix checkbox to the left side 
                'model' => $dataprovider, //model is used to get attribute labels
                'columns'=>array(
                                array(
                                    'name'=>'mailTemplate.name',
                                    'filter'=>CHtml::activeTextField($dataprovider, 'mailTemplate'),
                                ),
                                'sendDate',
                                array(
                                        'name'=>'mailTemplate.subject',
                                        'filter'=>CHtml::activeTextField($dataprovider, 'mailTemplate'),
                            ),
                            array(
                                'name'=>'client.email',
                                'filter'=>CHtml::activeTextField($dataprovider, 'client'),
                            ),
                            array(
                                'name'=>'client.name',
                                'filter'=>CHtml::activeTextField($dataprovider, 'client'),
                            ),
                            array(
                                'name'=>'operator.username',
                                'filter'=>CHtml::activeTextField($dataprovider, 'operator'),
                            ),
                            array(
                                'name'=>'status',
                                'value'=>array('MailHelper', 'getEmailStatus'),
                                'filter'=> CHtml::activeDropDownList($dataprovider, 'status', Mail::getEmailStatuses()),
                            ),
                            array(
                                'class'=>'CButtonColumn',
                                'template'=>'{update}',
                                'buttons'=>array(
                                                'update' => array(
                                                        'url'=>'$this->grid->controller->createUrl("/email/editTemplate", array("templateId"=>$data->id))',
                                                ),
                                            ),
                            )
                        ),
        )
    ));

?>

<?php $this->widget('zii.widgets.grid.CGridView', array(
    'id' => 'mails-grid',
    'dataProvider'=>$dataprovider->search(),
    'columns' => $dialog->columns(),
    'filter' => $dataprovider,
    'template' => $dialog->link()."{summary}\n{items}\n{pager}",
)); ?>

Solution

  • I have Restaurant, City, Country and User models with relations between them.

    Model:

    public function search() {
      $criteria=new CDbCriteria;
      $criteria->together = true;
      $criteria->with= array('xCountry','xCity','User');
      $criteria->compare('Id',$this->Id,true);
      $criteria->compare('Restaurant.Name',$this->Name,true);
      $criteria->addSearchCondition('xCountry.Name',$this->Country);
      $criteria->addSearchCondition('xCity.Name',$this->City);
      $criteria->compare('Zip',$this->Zip,true);
      $criteria->compare('Address',$this->Address,true);
      $criteria->compare('Description',$this->Description,true);
      $criteria->compare('Restaurant.Active',$this->Active,true);
      $criteria->addSearchCondition('User.Username',$this->Owner);
      $criteria->compare('Lat',$this->Lat);
      $criteria->compare('Lon',$this->Lon);
    
      return new CActiveDataProvider($this, array(
        'criteria'=>$criteria,
      ));
    }
    

    View:

    $this->widget('zii.widgets.grid.CGridView', array(
          'id'=>'restaurant-grid',
          'dataProvider'=>$model->search(),
          'filter'=>$model,
          'columns'=>array(
            'Id',
            'Name',
            'Zip',
            'Address',
            'Active',
            array(
              'name' => 'User.Username',
              'header' => 'Username',
              'filter' => CHtml::activeTextField($model, 'Owner'),
              'value' => '$data->User->Username',
                ),
            array(
              'name' => 'xCountry.Name',
              'header' => 'Country',
              'filter' => CHtml::activeTextField($model, 'Country'),
              'value' => '$data->xCountry->Name',
                ),
            array(
              'name' => 'xCity.Name',
              'header' => 'City',
              'filter' => CHtml::activeTextField($model, 'City'),
              'value' => '$data->xCity->Name',
                ),
            array(
            'class'=>'CButtonColumn',
            ),
          ),
        ));
    

    I hope this can help you.

    UPDATE:

    What if you try something like this:

    ...
    'columns'=>array(
      'mailTemplate.name',
      'sendDate',
      'mailTemplate.subject',
      'client.email',
      ...
    

    UPDATE #2:

    Prepare yourself this will be a bit dirty.

    Let's say we've got two classes, A and B. B belongs to A. B's got a property, let's say "color" and we want to display it in our grid where we list the "A"s.

    The first thing you have to do is, manually create a property to your data provider class (what is "A"). This property will be "colorOfB", so you have to add "public $colorOfB;" to your model A.

    Add criteria for this property:

    $criteria->compare('B.color',$this->colorOfB,true);
    

    Add the column to the grid:

    array(
      'name' => 'B.color',
      'header' => 'Color of B',
      'filter' => CHtml::activeTextField($model, 'colorOfB'),
      'value' => '$data->B->color'),
    

    The final thing is to set this property manually in A's controller:

    $modelA = new A('search');
    $modelA->colorOfB = $_GET['A']['colorOfB'];