Табличный вывод данных из двух таблиц с помощью CGridView в Yii 1.0
2011-06-23
Часто нужно создать табличный вывод записей из таблицы, особенно когда делают back-клиенте. Сложности здесь особой нет, тем более что с помощью gii можно это сделать автоматически. Сложность возникает когда нужно отобразить связанные записи из двух таблиц.

Сначала создадим две таблицы

CREATE TABLE `city` (
  `id` int(11) NOT NULL auto_increment,
  `name_city` varchar(64) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=cp1251 AUTO_INCREMENT=4 ;

INSERT INTO `city` VALUES (1, 'Москва');
INSERT INTO `city` VALUES (2, 'Санкт-Петербург');
INSERT INTO `city` VALUES (3, 'Выборг');

CREATE TABLE `name` (
  `id` int(11) NOT NULL,
  `name_person` varchar(64) NOT NULL,
  `id_city` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `id_city` (`id_city`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;

INSERT INTO `name` VALUES (0, 'Иван', 1);
INSERT INTO `name` VALUES (1, 'Михаил', 2);
INSERT INTO `name` VALUES (2, 'Алексей', 3);
INSERT INTO `name` VALUES (3, 'Вячеслав', 2);
INSERT INTO `name` VALUES (4, 'Даша', 1);

Таблица city связана с таблицей name отношением один-к-многим, через поле id_city.

Создаем две модели

<?php
// models/city.php
class city extends CActiveRecord
{
    /**
     * The followings are the available columns in table 'name':
     * @var integer $id
     * @var string $name_city
     */
    
    /**
     * Returns the static model of the specified AR class.
     * @return CActiveRecord the static model class
     */
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }

    /**
     * @return string the associated database table name
     */
    public function tableName()
    {
        return 'city';
    }
}
<?php
// models/name.php
class name extends CActiveRecord
{
    /**
     * The followings are the available columns in table 'name':
     * @var integer $id
     * @var string $name_person
     * @var integer $id_city
     */
    
    /**
     * Returns the static model of the specified AR class.
     * @return CActiveRecord the static model class
     */
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }

    /**
     * @return string the associated database table name
     */
    public function tableName()
    {
        return 'name';
    }
    
    public function rules()
    {
        return array(
            // The following rule is used by search().
            array('id, name_person, nameCity', 'safe', 'on'=>'search'),
        );
    }
    
    public function attributeLabels()
    {
        return array(
            'id' => 'Id',
            'name_person' => 'Name',
            'nameCity' => 'City',
        );
    }
    
    /**
     * Отношения name с другими таблицами
     */
    public function relations()
    {
        return array(
            'nameCity'=>array(self::BELONGS_TO, 'city', 'id_city'),
        );
    }
    
    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
    public function search()
    {
        $criteria=new CDbCriteria;
        $criteria->compare('t.id',$this->id);
        $criteria->compare('name_person',$this->name_person,true);
        
        $criteria->with=array('nameCity'); // жадная загрузка
        $criteria->compare('nameCity.name_city',$this->nameCity,true); // поиск по связанному полю
        
        return new CActiveDataProvider('name', array(
            'criteria'=>$criteria,
            'sort'=>array('attributes'=>array(
                'nameCity'=>array( // сортировка по связанном полю
                    'asc' => $expr='nameCity.name_city',
                    'desc' => $expr.' DESC',
                ),
                'id'=>array( // сортировка по id 
                    'asc' => $expr='t.id', // t.id написано потому что у нас id есть в двух таблицах
                    'desc' => $expr.' DESC',
                ),
                'name_person', // не требует подробного описания т.к. это поле индивидуально для двух таблиц
            )),
            'pagination'=>array(
                'pageSize'=>40, // количество записей на странице
            ),
        ));
    }
}

Создаем контроллер

<?php
// controllers/SiteController.php
class SiteController extends Controller
{
    public function actionView()
    {
        $model=new name('search');
        if(isset($_GET['name']))
            $model->attributes=$_GET['name'];
            
        $this->render('view',array(
            'model'=>$model,
        ));
    }
}

Создаем отображение

<?php // views/site/view.php ?>
<?php
Yii::app()->clientScript->registerScript('search', "
$('.search-button').click(function(){
    $('.search-form').toggle();
    return false;
});
$('.search-form form').submit(function(){
    $.fn.yiiGridView.update('name-grid', {
        data: $(this).serialize()
    });
    return false;
});
");
?>

<?php echo CHtml::link('Advanced Search','#',array('class'=>'search-button')); ?>
<div class="search-form" style="display:none">
<?php $this->renderPartial('_search',array(
    'model'=>$model,
)); ?>
</div><!-- search-form -->

<?php $this->widget('zii.widgets.grid.CGridView', array(
    'id'=>'name-grid',
    'dataProvider'=>$model->search(),
    'filter'=>$model,
    'columns'=>array(
        'id',
        'name_person',
        array(
            'name'=>'nameCity',
            'value'=>'$data->nameCity->name_city',
            'sortable'=>true,
        ),
        array(
            'class'=>'CButtonColumn',
        ),
    ),
)); ?>

И форму для поиска

<?php // views/site/_search.php ?>
<div class="wide form">

<?php $form=$this->beginWidget('CActiveForm', array(
    'action'=>Yii::app()->createUrl($this->route),
    'method'=>'get',
)); ?>

    <div class="row">
        <?php echo $form->label($model,'id'); ?>
        <?php echo $form->textField($model,'id'); ?>
    </div>

    <div class="row">
        <?php echo $form->label($model,'name_person'); ?>
        <?php echo $form->textField($model,'name_person',array('size'=>60,'maxlength'=>64)); ?>
    </div>

    <div class="row">
        <?php echo $form->label($model,'nameCity'); ?>
        <?php echo $form->textField($model,'nameCity'); ?>
    </div>

    <div class="row buttons">
        <?php echo CHtml::submitButton('Search'); ?>
    </div>

<?php $this->endWidget(); ?>

</div><!-- search-form -->

В итоге мы имеем табличный вывод данных с сортировкой по колонкам и поиск.

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

www.000webhost.com