Added TreeBehavior::generateTreeArray(), the big brother of TreeBehavior::generateTreeList() #1660

Closed
wants to merge 2 commits into
from

Conversation

Projects
None yet
3 participants

The method TreeBehavior::generateTreeList() generates a simple array of only the record id and name of the node and its corresponding spacer to indicate its hierarchy. However, such list might limit you to the things you can do.

So, I created a recursive method TreeBehavior::generateTreeArray(), which returns an associative array of the record. And the method also allows you to sort by any other custom fields or add other conditions if needed.

FYI commit a632769 has the codes that passes phpcs --standard=CakePHP tests.

You can see a screenshot of the final output below. The first array is from TreeBehavior::generateTreeList(), while the second array is from TreeBehavior::generateTreeArray().

screen shot 2013-09-19 at 11 34 51 pm

rooseveltrp added some commits Sep 20, 2013

Added a method called generateTreeArray() under
/lib/Cake/Model/Behavior/TreeBehavior.php. Allows you to create a
hierarchical array list of the records

Added a testGenerateTreeArray under
/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php to test
the generateTreeArray() method.
UPDATED the code to match the CakePHP coding standards. Passes 'phpcs
--standard=CakePHP' test

- Added a method called generateTreeArray() under
/lib/Cake/Model/Behavior/TreeBehavior.php. Allows you to create a
hierarchical array list of the records

- Added a testGenerateTreeArray under
/lib/Cake/Test/Case/Model/Behavior/TreeBehaviorNumberTest.php to test
the generateTreeArray() method
Member

ADmad commented Sep 20, 2013

Exactly what usage limitations are you facing?

Your generateTreeArray is called recursively thereby doing multiple db queries negating the benefits of using MPTT structure.

I ran into two issues with generateTree(). First it was returning an array of srings. I was struggling to configure the keyPath or the valuePath but could not make it return the above array generateTreeArray() returns. I also have another column in the table called order. So, you can order the records first by its hierarchy and then by its custom order number. Since, generateTreeList() only orders by Left, it did not have room to order by my custom order afterwards.

I can update the code to use MPTT... I did not realize MPTT was designed to avoid multiple queries.

By the way I noticed when Travis is testing using PGSQL the value of the ID column is returned as an integer while MySQL and SqLite databases returns the ID column as a string. Doesn't PHP enforce that these values are always integer? I will have to update the tests case as well so it passes for all databases.

Owner

markstory commented Sep 20, 2013

How does this differ from find(threaded). The results look the same as far as I can tell.

Member

ADmad commented Sep 20, 2013

Ordering MPTT nodes by anything other than lft field will just fail.

The problem with threaded is it puts the children records under another index called Children. While generateTreeArray() puts all the records (including its children) sequentially. And has the tree_prefix to show its hierarchy. This allows you to loop through the records in a single foreach or while loop.

But find("threaded") will require you to use some kind of recursive loop to properly iterate through the records and its nested children.

ADmad my original code was using MPTT but I think I changed it to use recursion so my custom ordering would work.

If you have a dataset like below:

1. Root
    1.2  `order 2` 
    1.1  `order 1`

generateTreeList would or cannot make sense of the order column values. So, you end up with records that don't look visually appealing. But using generateTreeArray() you can create a list and have them ordered nicely like below:

1. Root
    1.1 `order 1`
    1.2 `order 2`
Owner

markstory commented Sep 20, 2013

@ADmad You should be able to sort by lft and another column as well. But I agree it is a bit strange as mptt trees are usually pre-ordered as the whole point is to be optimized for reads.

@rooseveltrp Ah I missed those details.

Member

ADmad commented Sep 20, 2013

@markstory Using a second column for ordering would make sense only if first column is going to have non-unique values but in MPTT values for lft will always be unique.

@rooseveltrp Your generateTreeArray function doesn't use MPTT features (lft, rght fields) and so in it's current state it's unacceptable to be added to TreeBehavior. And if you are also want custom ordering MPTT is not the right structure for your needs.

Its a shame the MPTT artifact doesn't support ordering by other fields. Would you recommend some other place where generateTreeArray() might fit better... (e.g. Model::find("tree")). Its a handy function and will save other developers some time... and its always nice to have something that works out of the box.

Member

ADmad commented Sep 20, 2013

I don't think any extra function needs to be added to the core. You can just make a plugin with a behavior and share it with the community by submitting it to plugins.cakephp.org

Cool. Thanks, I will do that. I am closing the request :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment