Вывод вложенных данных в CGridView

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
Ответить
vyrtime
Сообщения: 5
Зарегистрирован: 2014.11.13, 09:45

Вывод вложенных данных в CGridView

Сообщение vyrtime »

Здравствуйте! Я новичок в Yii, поэтому прошу помощи.

Есть 3 таблицы - tbl_auto, tbl_file и tbl_model_file и, соответственно, 3 модели: Auto (авто), File (файлы), ModelFile (таблица для связки авто и файлов).

Прописаны следующие связи:

В модели Auto:

Код: Выделить всё

/**
* @return array relational rules.
*/
public function relations()
{
    return array(
        'modelFiles' => array(self::HAS_MANY, 'ModelFile', 'model_id'),
        'KdFiles' => array(self::HAS_MANY, 'File', array('file_id'), 'through'=>'modelFiles'),
    );
}
 
В модели File:

Код: Выделить всё

public function relations()
{
    return array(
        'modelFiles' => array(self::HAS_MANY, 'ModelFile', 'file_id'),
    );
}
 
В модели ModelFile:

Код: Выделить всё

public function relations()
{
    return array(
        'file' => array(self::BELONGS_TO, 'File', 'file_id'),
        'model' => array(self::BELONGS_TO, 'Auto', 'model_id'),
    );
}
 
К каждому авто можно добавить файлы. Файлы никогда не повторяются, т.е. уникальны. Один и тот же файл может встречаться в нескольких авто. Для более удобной работы с авто была придумана на странице обновления конкретного авто таблица со всеми авто и вложенных в каждый авто файлов.
На странице обновления (контроллер actionUpdate) модели Auto в файле _form.php и была выведена таблица со списком всех моделей Auto со списком имеющихся файлов в каждом авто.
Внимание! Лицам, не привыкшим к нижеприведенному *овнокоду категорически запрещается дальнейший просмотр :oops: :) .

Код: Выделить всё

// загружаем все авто
if(empty($model->id))
    $autos=Auto::model()->findAll();
else
    $autos=Auto::model()->findAll('id!=:id',array(':id'=>$model->id)); // кроме текущего авто
            
    if(!empty($autos))
    {
        // формируем массив из авто с файлами
        $all_files = array();
        foreach($autos as $auto)
        {
            $all_files[]=$auto;
            $auto_files=$auto->KdFiles;
            foreach($auto_files as $file)
                        $all_files[] = $file;
    }
                
    $itemsProvider = new CArrayDataProvider($all_files,array(
                    'pagination'=>false,
            )
        );
            
    // загрузка файлов КД текущей модели авто
    $auto=Auto::model()->findByPk($model->id);
    $auto_files=$auto->KdFiles;
    if(!empty($auto->KdFiles))
    {
        foreach($auto->KdFiles as $file)
            $auto_files_kd[] = $file->name;
    }
                    
    echo "<h2>Реестр изделий</h2>";
                
    // EScrollableGridView - плагин, позволяющий фиксировать заголовки таблиц, используется вместо CGridView
    $this->widget('EScrollableGridView', array(
            'height' => '400',
            'width' => '0',
            'id' => 'itemGrid',
            'dataProvider' => $itemsProvider,
            'rowHtmlOptionsExpression' => 'empty($data->name) ? array("id"=>"auto_".$data->id) : array()',
            'rowCssClassExpression'=>function($row, $data, $model) use ($basket){
            global $auto_id;
                        $class = $row % 2 ? 'even' : 'odd';
                        if(!isset($data->name))
                        {
                            $auto = Auto::model()->findByPk($data->id);
                            if($auto)
                            {
                                if(isset($auto->model_number))
                                    $auto_id = $auto->id;
                            }
                        }
                        
                        if(isset($data->name))
                            $class .= ' kdfiles auto_'. $auto_id;
                        else
                            $class = 'auto';
                        return $class;
                    },
        'columns' => array(
                        array(
                            'class' => 'CCheckBoxColumn',
                            'selectableRows' => 2,
                            'checkBoxHtmlOptions' => array(
                                'name' => 'Auto[auto_kd_drag][]',
                            ),
                            'value'=>function($data, $row) use ($auto_files_kd){
                                if(!empty($data->name))
                                    return $data->id;
                                else
                                    return NULL;
                            },
                            'disabled'=>function($data, $row) use ($auto_files_kd){
                                if(!empty($data->name))
                                {
                                    if(is_array($auto_files_kd))
                                        return in_array($data->name, $auto_files_kd);
                                }
                                else
                                    return 'disabled';
                            },
                            'checked'=>function($data, $row) use ($auto_files_kd){
                                if(!empty($data->name))
                                {
                                    if(is_array($auto_files_kd))
                                        return in_array($data->name, $auto_files_kd);
                                }
                            },
                            'htmlOptions'=>array( 'class'=>'center'),
                        ),
                        array(
                            'header'=>'Код изделия',
                            'type'=>'raw',
                            'name'=>'model_name',
                            'value'=>'!empty($data->name) ? "<div class=button-column2>". CHtml::link($data->name,array(Yii::app()->createUrl("/file/". $data->id)),array("target"=>"_blank", "class"=>"update")). "</div>". $data->name : "$data->model_number"',
                        ),
                        array(
                            'header'=>'Тип файла',
                            'type'=>'raw',
                            'value'=>'isset($data->file_type_id) ? FileType::model()->find("id=:fileTypeId", array(":fileTypeId"=>$data->file_type_id))->description : ""',
                        ),
                        array(
                            'header'=>'Дата создания',
                            'type'=>'raw',
                            'value'=>'!empty($data->create_time) ? date("d.m.Y", strtotime($data->create_time)) : ""',
                        ),
                    ),
                ));
            }
Данная таблица выводит список всех моделей с вложенными файлами к каждому авто. Также на этой странице выводится список файлов текущего авто. Т.е. вышеприведенная таблица предназначена для переноса файлов из разных моделей авто к текущей.
1. Как правильно выводить таблицу со связанными данными (т.е. у каждого авто свои файлы)?
2. Не получается сделать сортировку и фильтрацию. Как её сделать?
badjo
Сообщения: 188
Зарегистрирован: 2013.10.10, 12:39

Re: Вывод вложенных данных в CGridView

Сообщение badjo »

Я так понимаю, есть таблицы "Автомобили" и "Файлы". У каждого авто множество файлов и наоборот. (связь многие ко многим).
В данном случае связь описывается как MANY_MANY, через вспомогательную таблицу

Код: Выделить всё

'files' => array(self::MANY_MANY, 'tbl_files', 'tbl_auto_file(id_auto, id_file)'),
Так можно получить все файлы по любому авто и наоборот.
vyrtime
Сообщения: 5
Зарегистрирован: 2014.11.13, 09:45

Re: Вывод вложенных данных в CGridView

Сообщение vyrtime »

Спасибо за ответ
Видимо я неверно выразился, вот примерно то, что я хотел http://www.yiiframework.com/forum/index ... B2-%D0%BF/

Только мне нужно, чтобы таблица отображалась так, чтобы каждая строка авто содержала ниже себя ещё строки с файлами.
badjo
Сообщения: 188
Зарегистрирован: 2013.10.10, 12:39

Re: Вывод вложенных данных в CGridView

Сообщение badjo »

vyrtime писал(а):Спасибо за ответ
Только мне нужно, чтобы таблица отображалась так, чтобы каждая строка авто содержала ниже себя ещё строки с файлами.
Объявляем свойство в классе "Автомобили".

Код: Выделить всё

protected $files_array;

 public function rules(){
        return array(
            array('filesArray', 'safe');
        );
    }
    
    public function relations()
    {
        return array(
            'files'=>array(self::MANY_MANY, 'Files', '{{auto_files}}(auto_id, file_id)'),
        ),
    );
    // геттер сеттер
    public function getАilesArray()
    {
        if ($this->files_array===null)
            $this->files_array=CHtml::listData($this->files, 'id', 'id');
        return $this->files_array;
    }   
 
    public function setАilesArray($value)
    {
        $this->files_array=$value;
    }
 
Далее для каждого автомобиля получаем массив файлов $filesArray.
На счет ниже строк не знаю, а в строке foreach вывести можно.
vyrtime
Сообщения: 5
Зарегистрирован: 2014.11.13, 09:45

Re: Вывод вложенных данных в CGridView

Сообщение vyrtime »

Спасибо, файлы автомобиля выводятся, но что передать в CArrayDataProvider и вывести через виджет с фильтрацией и сортировкой CGridView, чтобы получилась таблица такого типа со следующими строками:
- Авто 1
- Чертеж к авто 1 №1
- Чертеж к авто 1 №2
- Чертеж к авто 1 №N
- Авто 2
- Чертеж к авто 2 №1
- Чертеж к авто 2 №2
- Чертеж к авто 2 №N
- Авто N
- Чертеж к авто N №1
- Чертеж к авто N №2
- Чертеж к авто N №N
badjo
Сообщения: 188
Зарегистрирован: 2013.10.10, 12:39

Re: Вывод вложенных данных в CGridView

Сообщение badjo »

Так с CGridView сделать не получится.
Можно использовать например CQTreeGridView viewtopic.php?t=2770
vyrtime
Сообщения: 5
Зарегистрирован: 2014.11.13, 09:45

Re: Вывод вложенных данных в CGridView

Сообщение vyrtime »

Спасибо большое, буду пробовать через CQTreeGridView
badjo
Сообщения: 188
Зарегистрирован: 2013.10.10, 12:39

Re: Вывод вложенных данных в CGridView

Сообщение badjo »

vyrtime писал(а):Спасибо большое, буду пробовать через CQTreeGridView
Хотя если поизвращаться с массивами моделей и потом вывести через CArrayDataProvider, возможно. Но очень муторно получиться.
Ответить