TreeCFC
All code licensed under
the Apache 2.0 license.
This cfc manages data trees. An example of a potential application
is a categorized menu or perhaps a corporate work structure. There are many
methods to manage trees available. Some are very complicated to deal with
and manage. Others cpu intensive. Most a pain in the ass! (Thats a type of
donkey to you).
The output of the cfc is a query with the following columns.
1: id. A uuid unique to this record.
2: levelafter. Either blank, or a string of - chars. This represents decreasing
levels in the tree as you traverse the query.
3: levelbefore. Either blank or a string of + chars. This represents increasing
levels in the tree as you traverse the query.
4: levelindex. Represents how many levels this record is at.
5+: Any user defined variables defined in the init function.
Setup
First we need a table to store the data in. Here is the mysql Dump.
DROP TABLE IF EXISTS `tre_tree`;
CREATE TABLE `tre_tree` (
`tre_uuid` varchar(35) NOT NULL default '',
`tre_id` varchar(255) NOT NULL default '',
`tre_value1` varchar(255) default NULL,
`tre_value2` varchar(255) default NULL,
`tre_value3` varchar(255) default NULL,
`tre_value4` varchar(255) default NULL,
`tre_value5` varchar(255) default NULL,
`tre_groupname` varchar(50) NOT NULL default '',
PRIMARY KEY (`tre_uuid`),
KEY `idx_tre_uuid` (`tre_uuid`),
KEY `idx_tre_id` (`tre_id`)
) TYPE=MyISAM;
I imagine a similar table would work for sql2k and oracle but I havent tested.
Initialize the tree
create the tree object, the init variables are :
1: The variables you will want in a comma delimited list.
2: The name of the tree. You can have multiple trees.
3: The dsn.
<cfset mytree = createObject("component","tree")>
<cfset mytree.init('label,path', 'menu', 'tre')>
Add some data
<cfset a = structnew()>
<cfset a.label = "A">
<cfset a.path = "firstitem.html">
<cfset firstid = mytree.add(a)>
<cfset a = structnew()>
<cfset a.label = "B">
<cfset a.path = "seconditem.html">
<cfset secondid = mytree.add(a)>
<cfset a.label = "C">
<cfset a.path = "thirditem.html">
<cfset thirdid = mytree.add(a)>
<cfset a = structnew()>
<cfset a.label = "D">
<cfset a.path = "fourthitem.html">
<cfset fourthid = mytree.add(a)>
<cfset a = structnew()>
<cfset a.label = "E">
<cfset a.path = "fifthitem.html">
<cfset fifthid = mytree.add(a)>
Now show the tree : mytree.gettree()
| query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
| 1 | 83CA7C38-3471-274A-68A8E5C886356CC4 | A | [empty string] | + | 1 | firstitem.html |
| 2 | 83CA7C4C-3471-274A-610916A469657916 | B | [empty string] | [empty string] | 1 | seconditem.html |
| 3 | 83CA7C56-3471-274A-636D7C0487EE8AA0 | C | [empty string] | [empty string] | 1 | thirditem.html |
| 4 | 83CA7C60-3471-274A-6FE8105546DA1402 | D | [empty string] | [empty string] | 1 | fourthitem.html |
| 5 | 83CA7C74-3471-274A-68096FD9D031397C | E | - | [empty string] | 1 | fifthitem.html |
Next, we'll add a sub-item or two
<cfset a = structnew()>
<cfset a.label = "C-A">
<cfset a.path = "thirdsubitem1.html">
<cfset threepointone = mytree.add(a, thirdid)>
<cfset a = structnew()>
<cfset a.label = "C-B">
<cfset a.path = "thirdsubitem2.html">
<cfset threepointtwo = mytree.add(a, thirdid)>
Now show the tree again : mytree.gettree()
| query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
| 1 | 83CA7C38-3471-274A-68A8E5C886356CC4 | A | [empty string] | + | 1 | firstitem.html |
| 2 | 83CA7C4C-3471-274A-610916A469657916 | B | [empty string] | [empty string] | 1 | seconditem.html |
| 3 | 83CA7C56-3471-274A-636D7C0487EE8AA0 | C | [empty string] | [empty string] | 1 | thirditem.html |
| 4 | 83CA7D29-3471-274A-61C250A009BEE764 | C-A | [empty string] | + | 2 | thirdsubitem1.html |
| 5 | 83CA7D33-3471-274A-6EEAD6AFF6B180F9 | C-B | - | [empty string] | 2 | thirdsubitem2.html |
| 6 | 83CA7C60-3471-274A-6FE8105546DA1402 | D | [empty string] | [empty string] | 1 | fourthitem.html |
| 7 | 83CA7C74-3471-274A-68096FD9D031397C | E | - | [empty string] | 1 | fifthitem.html |
Hey, that was fun! Do it again!
<cfset a = structnew()>
<cfset a.label = "D-A">
<cfset a.path = "fourthsubitem1.html">
<cfset fourpointone = mytree.add(a, fourthid)>
<cfset a = structnew()>
<cfset a.label = "D-A-A">
<cfset a.path = "fourpointonepointone.html">
<cfset fourpointonepointone = mytree.add(a, fourpointone)>
<cfset a = structnew()>
<cfset a.label = "D-A-B">
<cfset a.path = "fourpointonepointtwo.html">
<cfset fourpointone = mytree.add(a, fourpointone)>
Now show the tree again.
| mytree.gettree() - query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
| 1 | 83CA7C38-3471-274A-68A8E5C886356CC4 | A | [empty string] | + | 1 | firstitem.html |
| 2 | 83CA7C4C-3471-274A-610916A469657916 | B | [empty string] | [empty string] | 1 | seconditem.html |
| 3 | 83CA7C56-3471-274A-636D7C0487EE8AA0 | C | [empty string] | [empty string] | 1 | thirditem.html |
| 4 | 83CA7D29-3471-274A-61C250A009BEE764 | C-A | [empty string] | + | 2 | thirdsubitem1.html |
| 5 | 83CA7D33-3471-274A-6EEAD6AFF6B180F9 | C-B | - | [empty string] | 2 | thirdsubitem2.html |
| 6 | 83CA7C60-3471-274A-6FE8105546DA1402 | D | [empty string] | [empty string] | 1 | fourthitem.html |
| 7 | 83CA7E0F-3471-274A-68FEB536CF5F68FF | D-A | [empty string] | + | 2 | fourthsubitem1.html |
| 8 | 83CA7E2D-3471-274A-62EB51FE12102037 | D-A-A | [empty string] | + | 3 | fourpointonepointone.html |
| 9 | 83CA7E41-3471-274A-6F4FC53566AE2736 | D-A-B | -- | [empty string] | 3 | fourpointonepointtwo.html |
| 10 | 83CA7C74-3471-274A-68096FD9D031397C | E | - | [empty string] | 1 | fifthitem.html |
Move Branches
Lets move some stuff around.
We'll start by moving the third item and its siblings down to below the fourth item.
Please note, this moves items within their level.
<cfset mytree.moveit(thirdid, 'down')>
And show it : mytree.gettree()
| mytree.gettree() - query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
| 1 | 83CA7C38-3471-274A-68A8E5C886356CC4 | A | [empty string] | + | 1 | firstitem.html |
| 2 | 83CA7C4C-3471-274A-610916A469657916 | B | [empty string] | [empty string] | 1 | seconditem.html |
| 3 | 83CA7C60-3471-274A-6FE8105546DA1402 | D | [empty string] | [empty string] | 1 | fourthitem.html |
| 4 | 83CA7E0F-3471-274A-68FEB536CF5F68FF | D-A | [empty string] | + | 2 | fourthsubitem1.html |
| 5 | 83CA7E2D-3471-274A-62EB51FE12102037 | D-A-A | [empty string] | + | 3 | fourpointonepointone.html |
| 6 | 83CA7E41-3471-274A-6F4FC53566AE2736 | D-A-B | -- | [empty string] | 3 | fourpointonepointtwo.html |
| 7 | 83CA7C56-3471-274A-636D7C0487EE8AA0 | C | [empty string] | [empty string] | 1 | thirditem.html |
| 8 | 83CA7D29-3471-274A-61C250A009BEE764 | C-A | [empty string] | + | 2 | thirdsubitem1.html |
| 9 | 83CA7D33-3471-274A-6EEAD6AFF6B180F9 | C-B | - | [empty string] | 2 | thirdsubitem2.html |
| 10 | 83CA7C74-3471-274A-68096FD9D031397C | E | - | [empty string] | 1 | fifthitem.html |
And move them back
<cfset mytree.moveit(thirdid, 'up')>
And show it.
| mytree.gettree() - query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
| 1 | 83CA7C38-3471-274A-68A8E5C886356CC4 | A | [empty string] | + | 1 | firstitem.html |
| 2 | 83CA7C4C-3471-274A-610916A469657916 | B | [empty string] | [empty string] | 1 | seconditem.html |
| 3 | 83CA7C56-3471-274A-636D7C0487EE8AA0 | C | [empty string] | [empty string] | 1 | thirditem.html |
| 4 | 83CA7D29-3471-274A-61C250A009BEE764 | C-A | [empty string] | + | 2 | thirdsubitem1.html |
| 5 | 83CA7D33-3471-274A-6EEAD6AFF6B180F9 | C-B | - | [empty string] | 2 | thirdsubitem2.html |
| 6 | 83CA7C60-3471-274A-6FE8105546DA1402 | D | [empty string] | [empty string] | 1 | fourthitem.html |
| 7 | 83CA7E0F-3471-274A-68FEB536CF5F68FF | D-A | [empty string] | + | 2 | fourthsubitem1.html |
| 8 | 83CA7E2D-3471-274A-62EB51FE12102037 | D-A-A | [empty string] | + | 3 | fourpointonepointone.html |
| 9 | 83CA7E41-3471-274A-6F4FC53566AE2736 | D-A-B | -- | [empty string] | 3 | fourpointonepointtwo.html |
| 10 | 83CA7C74-3471-274A-68096FD9D031397C | E | - | [empty string] | 1 | fifthitem.html |
Get additional useful info
You can always request the brothers of an item.
For example, the C-A : mytree.getBrothers(threepointone).
| mytree.getBrothers(threepointone) - query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
| 1 | 83CA7D29-3471-274A-61C250A009BEE764 | C-A | [empty string] | + | 1 | thirdsubitem1.html |
| 2 | 83CA7D33-3471-274A-6EEAD6AFF6B180F9 | C-B | - | [empty string] | 1 | thirdsubitem2.html |
Or the kids of an item : mytree.getSubItems(fourpointone).
| mytree.getSubItems(fourpointone) - query |
| |
TRE_GROUPNAME | TRE_ID | TRE_UUID | TRE_VALUE1 | TRE_VALUE2 | TRE_VALUE3 | TRE_VALUE4 | TRE_VALUE5 |
| 1 | menu | 004.001.001 | 83CA7E2D-3471-274A-62EB51FE12102037 | D-A-A | fourpointonepointone.html | [empty string] | [empty string] | [empty string] |
| 2 | menu | 004.001.002 | 83CA7E41-3471-274A-6F4FC53566AE2736 | D-A-B | fourpointonepointtwo.html | [empty string] | [empty string] | [empty string] |
Or just an item : mytree.getItem(fourpointone)>.
| mytree.getItem(fourpointone) - query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
| 1 | 83CA7E0F-3471-274A-68FEB536CF5F68FF | D-A | - | + | 1 | fourthsubitem1.html |
Or the parent of an item : mytree.getParent(fourpointone).
| mytree.getparent(fourpointone) - query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
| 1 | 83CA7C60-3471-274A-6FE8105546DA1402 | D | - | + | 1 | fourthitem.html |
Or the get the whole parent set : allparents = mytree.getParents(fourpointonepointone).
| allparents - query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
| 1 | 83CA7C60-3471-274A-6FE8105546DA1402 | D | [empty string] | + | 1 | fourthitem.html |
| 2 | 83CA7E0F-3471-274A-68FEB536CF5F68FF | D-A | -- | + | 2 | fourthsubitem1.html |
Which is very useful if your trying to make a breadcrumb trail via valuelist :
valuelist(allparents.label," : ") yields D : D-A
Clear the tree
Finally clear the tree.
<cfset mytree.deletetree()>
And show that it was cleared : mytree.gettree()
| mytree.gettree() - query |
| |
ID | LABEL | LEVELAFTER | LEVELBEFORE | LEVELINDEX | PATH |
Download
V.5 TreeCFC