Специфическая сортировка в CActiveDataProvider

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
Ответить
ilyas.galiev
Сообщения: 39
Зарегистрирован: 2014.08.18, 10:04

Специфическая сортировка в CActiveDataProvider

Сообщение ilyas.galiev »

Сейчас есть категории, у категорий есть родители, которые прописываются как parent_id в таблице. Ну стандарт в общем.
Задача такова. Нужно отсортировать элементы так, чтобы сначала шли категории верхнего уровня, после категории верхнего уровня идут ее потомки, после потомка его потомки и т.д. + ко всему категории должны сортироваться по определенному полю, называемый "Порядок сортировки". Это просто число, которое обозначает номер в списке.

Можно ли так отсортировать данные в cactivedataprovider? Если да, то как примерно?
Если в dataprovider нельзя, то как лучше сделать?
Аватара пользователя
Insolita
Сообщения: 788
Зарегистрирован: 2011.06.06, 01:39
Контактная информация:

Re: Специфическая сортировка в CActiveDataProvider

Сообщение Insolita »

для такого проще всего добавить в бд поле level соотв. уровню вложенности (рассчитывать его в beforeSave) и соответственно по нему и сортировать иначе только бессмысленными и беспощадными извращениями с кучей джойнов
ilyas.galiev
Сообщения: 39
Зарегистрирован: 2014.08.18, 10:04

Re: Специфическая сортировка в CActiveDataProvider

Сообщение ilyas.galiev »

У меня уже есть такое поле. Просто не соображу как сделать правильно
ilyas.galiev
Сообщения: 39
Зарегистрирован: 2014.08.18, 10:04

Re: Специфическая сортировка в CActiveDataProvider

Сообщение ilyas.galiev »

И, кстати, не обязательно использовать кучу джойнов. Логику можно описать примерно так: получить все необходимые данные, сохранить данные в удобный массив, допустим parent_id=>[...остальные данные...], и потом с помощью рекурсии отсортировать данные в нужном порядке. Остается вопрос как это провернуть с dataprovider
Аватара пользователя
Insolita
Сообщения: 788
Зарегистрирован: 2011.06.06, 01:39
Контактная информация:

Re: Специфическая сортировка в CActiveDataProvider

Сообщение Insolita »

если level есть то в чем проблема - указать

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

 
        $dataProvider=new CActiveDataProvider('YourModel', array(
            'criteria'=>$criteria,
            'sort'=>array(
                'defaultOrder'=>'level ASC, order ASC'
            ), 
            ...    
        ));  
         
http://www.yiiframework.com/doc/api/1.1/CSort
ilyas.galiev
Сообщения: 39
Зарегистрирован: 2014.08.18, 10:04

Re: Специфическая сортировка в CActiveDataProvider

Сообщение ilyas.galiev »

Я неправильно поставил вопрос. Допустим, есть такая иерархия категорий:

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

Книги
>Русские
>>Фантастика
>>Детективы
>Зарубежные
>>Наука
>>Сказки
Одежда
>Верхняя одежда
>>Куртки
>>Пальто
Мне нужно сначала по полю "Порядок сортировки" отсортировать категории верхнего уровня, потом после каждой категории верхнего уровня идут ее потомки, как я указал выше. И потомков тоже нужно отсортировать по полю "Порядок сортировки". Был бы массив - проблем бы не возникло, но я не знаю как это сделать с CADP
Аватара пользователя
SiZE
Сообщения: 2813
Зарегистрирован: 2011.09.21, 12:39
Откуда: Perm
Контактная информация:

Re: Специфическая сортировка в CActiveDataProvider

Сообщение SiZE »

ilyas.galiev писал(а):Мне нужно сначала по полю "Порядок сортировки" отсортировать категории верхнего уровня, потом после каждой категории верхнего уровня идут ее потомки, как я указал выше. И потомков тоже нужно отсортировать по полю "Порядок сортировки". Был бы массив - проблем бы не возникло, но я не знаю как это сделать с CADP
Есть два варианта. Написать функцию, которая будет получать список элементов первого уровня, проверять есть ли у них потомки, получать их и т.д. Второй вариант организовать такую структуру:

name | level | number | position (varchar(255) обеспечивает 99999 элементов на уровне и 51 уровень вложенности)

Книги | 1 | 1 | 00001
Русские | 2 | 1 | 0000100001
Фантастика | 3 | 1 | 000010000100001
Детективы | 3 | 2 | 000010000100002
Наука | 2 | 2 | 0000100002
Сказки | 2 | 3 | 0000100003
Одежда | 1 | 2 | 00002

ORDER BY position и все.

position (varchar(255) обеспечивает 99999 элементов на уровне и 51 уровень вложенности). Но зачастую и 999 элементов за глаза и 5 уровней вложености.
ilyas.galiev
Сообщения: 39
Зарегистрирован: 2014.08.18, 10:04

Re: Специфическая сортировка в CActiveDataProvider

Сообщение ilyas.galiev »

Пришлось сделать так. Не знаю говнокод ли это, но работает. Если так вариант плохой, то как сделать лучше?

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

private static $_dp;
    private static $_dp_arr;
    private static $_sorted_dp;
    public function search () {

        $criteria = new CDbCriteria;
        if(isset($this->mixedSearch)) {
            $criteria->addSearchCondition('id', $this->mixedSearch);
            $criteria->addSearchCondition('name', $this->mixedSearch, true, 'OR');
        }

        self::$_dp = new CActiveDataProvider($this, array(
            'criteria' => $criteria,
            'pagination' => [
                'pageSize' => self::$per_page,
                'pageVar' => 'page',
            ],
            'sort' => [
                'sortVar' => 'sort',
                'defaultOrder' => 't.level ASC, t.order ASC',
            ]
        ));
        self::fetchProvider();
        self::$_dp->data = self::$_sorted_dp;
        return self::$_dp;
    }

    private static function fetchProvider() {
        foreach(self::$_dp->data as $data) {
            self::$_dp_arr[$data->parent_id][$data->id] = $data;
        }
        self::fetchProvider_addChild('',0);
    }
    private static function fetchProvider_addChild($parent, $lvl) {
        if(isset(self::$_dp_arr[$parent])) {
            foreach(self::$_dp_arr[$parent] as $k => $v) {
                $offset =  str_repeat(' >> ',$lvl);
                $v->name = $offset . $v->name;
                self::$_sorted_dp[] = $v;
                $lvl++;
                self::fetchProvider_addChild($k, $lvl);
                $lvl--;
            }
        }
    }
Ответить