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
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH
183CA7C38-3471-274A-68A8E5C886356CC4A[empty string]+1firstitem.html
283CA7C4C-3471-274A-610916A469657916B[empty string][empty string]1seconditem.html
383CA7C56-3471-274A-636D7C0487EE8AA0C[empty string][empty string]1thirditem.html
483CA7C60-3471-274A-6FE8105546DA1402D[empty string][empty string]1fourthitem.html
583CA7C74-3471-274A-68096FD9D031397CE-[empty string]1fifthitem.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
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH
183CA7C38-3471-274A-68A8E5C886356CC4A[empty string]+1firstitem.html
283CA7C4C-3471-274A-610916A469657916B[empty string][empty string]1seconditem.html
383CA7C56-3471-274A-636D7C0487EE8AA0C[empty string][empty string]1thirditem.html
483CA7D29-3471-274A-61C250A009BEE764C-A[empty string]+2thirdsubitem1.html
583CA7D33-3471-274A-6EEAD6AFF6B180F9C-B-[empty string]2thirdsubitem2.html
683CA7C60-3471-274A-6FE8105546DA1402D[empty string][empty string]1fourthitem.html
783CA7C74-3471-274A-68096FD9D031397CE-[empty string]1fifthitem.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
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH
183CA7C38-3471-274A-68A8E5C886356CC4A[empty string]+1firstitem.html
283CA7C4C-3471-274A-610916A469657916B[empty string][empty string]1seconditem.html
383CA7C56-3471-274A-636D7C0487EE8AA0C[empty string][empty string]1thirditem.html
483CA7D29-3471-274A-61C250A009BEE764C-A[empty string]+2thirdsubitem1.html
583CA7D33-3471-274A-6EEAD6AFF6B180F9C-B-[empty string]2thirdsubitem2.html
683CA7C60-3471-274A-6FE8105546DA1402D[empty string][empty string]1fourthitem.html
783CA7E0F-3471-274A-68FEB536CF5F68FFD-A[empty string]+2fourthsubitem1.html
883CA7E2D-3471-274A-62EB51FE12102037D-A-A[empty string]+3fourpointonepointone.html
983CA7E41-3471-274A-6F4FC53566AE2736D-A-B--[empty string]3fourpointonepointtwo.html
1083CA7C74-3471-274A-68096FD9D031397CE-[empty string]1fifthitem.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
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH
183CA7C38-3471-274A-68A8E5C886356CC4A[empty string]+1firstitem.html
283CA7C4C-3471-274A-610916A469657916B[empty string][empty string]1seconditem.html
383CA7C60-3471-274A-6FE8105546DA1402D[empty string][empty string]1fourthitem.html
483CA7E0F-3471-274A-68FEB536CF5F68FFD-A[empty string]+2fourthsubitem1.html
583CA7E2D-3471-274A-62EB51FE12102037D-A-A[empty string]+3fourpointonepointone.html
683CA7E41-3471-274A-6F4FC53566AE2736D-A-B--[empty string]3fourpointonepointtwo.html
783CA7C56-3471-274A-636D7C0487EE8AA0C[empty string][empty string]1thirditem.html
883CA7D29-3471-274A-61C250A009BEE764C-A[empty string]+2thirdsubitem1.html
983CA7D33-3471-274A-6EEAD6AFF6B180F9C-B-[empty string]2thirdsubitem2.html
1083CA7C74-3471-274A-68096FD9D031397CE-[empty string]1fifthitem.html
And move them back <cfset mytree.moveit(thirdid, 'up')> And show it.
mytree.gettree() - query
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH
183CA7C38-3471-274A-68A8E5C886356CC4A[empty string]+1firstitem.html
283CA7C4C-3471-274A-610916A469657916B[empty string][empty string]1seconditem.html
383CA7C56-3471-274A-636D7C0487EE8AA0C[empty string][empty string]1thirditem.html
483CA7D29-3471-274A-61C250A009BEE764C-A[empty string]+2thirdsubitem1.html
583CA7D33-3471-274A-6EEAD6AFF6B180F9C-B-[empty string]2thirdsubitem2.html
683CA7C60-3471-274A-6FE8105546DA1402D[empty string][empty string]1fourthitem.html
783CA7E0F-3471-274A-68FEB536CF5F68FFD-A[empty string]+2fourthsubitem1.html
883CA7E2D-3471-274A-62EB51FE12102037D-A-A[empty string]+3fourpointonepointone.html
983CA7E41-3471-274A-6F4FC53566AE2736D-A-B--[empty string]3fourpointonepointtwo.html
1083CA7C74-3471-274A-68096FD9D031397CE-[empty string]1fifthitem.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
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH
183CA7D29-3471-274A-61C250A009BEE764C-A[empty string]+1thirdsubitem1.html
283CA7D33-3471-274A-6EEAD6AFF6B180F9C-B-[empty string]1thirdsubitem2.html
Or the kids of an item : mytree.getSubItems(fourpointone).
mytree.getSubItems(fourpointone) - query
  TRE_GROUPNAMETRE_IDTRE_UUIDTRE_VALUE1TRE_VALUE2TRE_VALUE3TRE_VALUE4TRE_VALUE5
1menu004.001.00183CA7E2D-3471-274A-62EB51FE12102037D-A-Afourpointonepointone.html[empty string][empty string][empty string]
2menu004.001.00283CA7E41-3471-274A-6F4FC53566AE2736D-A-Bfourpointonepointtwo.html[empty string][empty string][empty string]
Or just an item : mytree.getItem(fourpointone)>.
mytree.getItem(fourpointone) - query
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH
183CA7E0F-3471-274A-68FEB536CF5F68FFD-A-+1fourthsubitem1.html
Or the parent of an item : mytree.getParent(fourpointone).
mytree.getparent(fourpointone) - query
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH
183CA7C60-3471-274A-6FE8105546DA1402D-+1fourthitem.html
Or the get the whole parent set : allparents = mytree.getParents(fourpointonepointone).
allparents - query
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH
183CA7C60-3471-274A-6FE8105546DA1402D[empty string]+1fourthitem.html
283CA7E0F-3471-274A-68FEB536CF5F68FFD-A--+2fourthsubitem1.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
  IDLABELLEVELAFTERLEVELBEFORELEVELINDEXPATH

Download

V.5 TreeCFC