开发者

Tree Behavior : how to quickly reorder existing data by a certain field?

开发者 https://www.devze.com 2023-02-17 20:15 出处:网络
I have a cakephp app with a category model that acts as a Tree. I imported ~100 categories through a csv file.

I have a cakephp app with a category model that acts as a Tree. I imported ~100 categories through a csv file.

I want to be able to quickly reorder all the categories by name so that my index view is ordered correctly.

I tried the reorder method from the Tree behavior :

$this->Category->reorder(array开发者_StackOverflow(
'id' => null,
'field' => 'Category.name',
'order' => 'ASC'
));

But it doesn't do anything. Am I missing something here ?

Thanks :)


I have just been looking into this and have come to the conclusion it is not possible to order the results in the generatetreelist() method - at least no easy way without looping through and manually moving each node. The best way to go about this is use the normal find method with the first argument as 'threaded', then you can apply SQL ordering like you would any query. I have this method in my Category model:

public function getThreaded($conditions = array()) {
    return $this->find('threaded', array(
        'order' => 'Category.name ASC',
        'contain' => false
    ));
}

This returns me an array of all my parent categories alphabetically-ordered, with a 'children' key containing another array all the children of that category, in alphabetical order too! I use contain => false to cut down on the data returned (threaded returns data about each node's parent, which we don't need to know), you could alter it to include extra data if need be.

I understand this isn't 100% the same as generatetreelist(), but it's certainly tidier and a lot more flexible as you control the output. If you really needed to emulate generatetreelist()'s behavior, you could just loop through the array from above like so:

$treeArray = array();
foreach($category as $parent) {
    $treeArray[] = $parent['Category']['name'];
    if(!empty($parent['children']) {
        foreach($parent['children'] as $childCategory) {
            $treeArray[] = ' - '.$childCategory['Category']['name'];
        }
    }
}

Hope this helps.


Just a reminder: the reorder() method from the Tree behavior only modifies the left and right fields of a tree following MPTT logic (which is the type of tree used by this behavior). It does not make all find() in that model magically deliver the order defined by your reorder() method. You still need to pass an order parameter in the find() options to actually use the updated left and right values.

Suppose you are using the default column names used by TreeBehavior: lft for the left field and rght for the right field. After running once the reorder() method given in the question, to get the ordered data from your Model to pass to your View, you would use something like:

$this->Category->find('all', array(
    'order' => array(
        'Category.lft' => 'ASC'
    )
));

Of course replacing the find type if you want to use something else than 'all'.

Ordering by Category.lft will in fact show you the order you would get by making a depth-first search, left to right - not an arbitrary order defined by the database like would happen if you had no order parameter, or if you used a simple 'order' => 'Category.name' in the find options which would ignore the tree structure.

P.S.: I know the question is 2 years old, but since nobody else explained what reorder() actually does, I think this would be useful.


If you are using the TreeLi helper to turn the results of generateTreeList into a UL/LI list, you can then use the jQuery plugin TinySort to sort the tree (http://tinysort.sjeiti.com/).

0

精彩评论

暂无评论...
验证码 换一张
取 消