nestedset + CMenu

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

nestedset + CMenu

Сообщение MOTORIST »

Не могу понять как реализовать эту связку. Вот здесь есть пример, но не получается
viewtopic.php?f=9&t=804&start=20

Не совсем понимаю как это использовать(во вьюшке):

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

$this->widget('zii.widgets.CMenu', array(
        'items'=>$root->getCMenuArray(array(
                        'returnrootnode'=>true,
                   )),
    )); 
 
Получаю:

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

Fatal error: Call to a member function getCMenuArray() on a non-object in protected/modules/backend/views/cat/index.php on line 34
По порядку:
в модели:

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

public function behaviors(){
        return array(
            'TreeBehavior' => array(
                'class' => 'application.extensions.nestedset.TreeBehavior',
                '_idCol' => 'id',
                '_lftCol' => 'lft',
                '_rgtCol' => 'rgt',
                '_lvlCol' => 'level',
            ),
            'TreeViewTreebehavior' => array(
                'class' => 'application.extensions.nestedset.TreeViewTreebehavior',
            ),
            'ArrayTreeBehavior' => array(
                'class' => 'application.extensions.nestedset.ArrayTreeBehavior',
            ),
        );
    }
 
В контроллере:

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

// создаем массив, который будем кормить CDropdownList и CListBox
        $data = CHtml::listData($model->findAll(array('order'=>'lft')), 'id', 'nameExt'); // Здесь переопределяем поле name на nameExt. Ниже описано зачем.
        $model = Cat::model()->findByPK(1); // Здесь вместо Categories меняем на свою модель
        $tree = $model->getTreeViewData(false);

        $this->render('index',array(
            'data'=>$data,
            'root'=>$tree,
        ));

 
ArrayTreeBehavior

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

class ArrayTreeBehavior extends TreeBehavior {

    public function getCMenuArray ($param = array()) {

        if (isset($param['rootaslink'])) {
            $rootaslink = $param['rootaslink'];
        } else {
            $rootaslink = false;
        }

        if (isset($param['returnrootnode'])) {
            $returnrootnode = $param['returnrootnode'];
        } else {
            $returnrootnode = false;
        }
        if (isset($param['keyfield'])) {
            $keyfield = $param['keyfield'];
        } else {
            $keyfield = '_id';
        }

        // Fetch the flat tree
        $rawtree = $this->getTree($returnrootnode);
        // Init variables needed for the array conversion
        $tree = array();
        $node =& $tree;
        $position = array();
        $lastitem = '';
        $depth = $this->getLevelValue();

        foreach($rawtree as $rawitem)
        {
            // If its a deeper item, then make it subitems of the current item
            if ($rawitem->getLevelValue() > $depth)
            {
                $position[] =& $node; //$lastitem;
                $depth = $rawitem->getLevelValue();
                $node =& $node[$lastitem]['items'];
            }
            // If its less deep item, then return to a level up
            else
            {
                while ($rawitem->getLevelValue() < $depth)
                {
                    end($position);
                    $node =& $position[key($position)];
                    array_pop($position);
                    $depth = $node[key($node)]['node']->getLevelValue();
                }
            }

            // Add the item to the final array
            $node[$rawitem->$keyfield]['node'] = $rawitem;
            if(!$rawitem->hasChildNodes() || $rootaslink)
                $node[$rawitem->$keyfield]['url'] = array($rawitem->owner->_url);
            $node[$rawitem->$keyfield]['label'] = $rawitem->owner->_name;
            // save the last items' name
            $lastitem = $rawitem->$keyfield;
        }
        // we don't care about the root node
        if (!$returnrootnode)
        {
            reset($tree);
            $tree = $tree[key($tree)]['items'];
            //array_shift($tree);
        }

        return $tree;
    }
}
 
В сознании новичка много возможностей, в сознании эксперта — лишь несколько.
navy
Сообщения: 21
Зарегистрирован: 2010.11.15, 12:59

Re: nestedset + CMenu

Сообщение navy »

У меня тоже не получилось подключить это поведение к модели, я сделал так

Я использую ext.yiiext.behaviors.model.trees.ENestedSetBehavior

в ENestedSetBehavior.php я добавил пару методов

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

        protected function tree2array($nodes) {
                $res = array();
                foreach($nodes as $n) {
                        $item = array('label'=>$n->menu, 'url'=>array('/тут нужный путь захардкодить/'.$n->id));
                                
                        if(!$n->isLeaf()) {
                                $item['items'] = $this->tree2array($n->children()->findAll());
                        }
                        $res[] = $item;
                }
                return $res;
        }
                                        
        public function getCMenuArray() {
                return $this->tree2array($this->children()->findAll());
        }

 
Чтобы не хардкодить путь его можно передавать как параметр (добавив этот параметр в оба метода) или сделать и использовать метод в модели который его возвращает.

Использование

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

$this->widget('application.extensions.CDropDownMenu',array(
    'items'=> Page::model()->findByPK(1)->getCMenuArray()),
);
 
Page::model()->findByPK(1) - так я получаю корень дерева

в модели Page есть поле menu, которое тут используется как текст меню.

Велосипед конечно, но разбираться что там не работает мне было некогда. Думаю что из этого можно сделать behavior, но пока нет времени
Ответить