Just a quick little tutorial on how to create display nested categories from a database using recursion and components. This is the simplest way I've found to accomplish recursion in ColdFusion, but feel free to comment if you know a better way.
In this tutorial, we are working with a single table in a SQL database with 3 columns: id, parent, name.
Here is the database structure:
CODE
categories
-----------------------------------
id (int, auto-increment, primary key)
parent (int)
name (nvarchar)
Create the componentCreate a new component called categories.cfc, start with this structure:
CODE
<cfcomponent name="Categories">
<cffunction name="getCats">
<!--- Parent ID --->
<cfargument name="parent" type="numeric">
</cffunction>
</cfcomponent>
As you may already know, recursion simply calls the same function from within itself. The beauty of using components is there is no need to number or name our function or objects because each call creates a new instance of the object.
Setup the queryIn the code above, we've created a function called getCats, it accepts 1 argument:
parent. We will use this argument to query for child categories.
CODE
<cfcomponent name="Categories">
<cffunction name="getCats">
<!--- Parent ID --->
<cfargument name="parent" type="numeric">
<!--- Query for Children of Parent --->
<cfquery name="qCats" datasource="YOUR_DATASOURCE">
SELECT * FROM categories WHERE parent = '#arguments.parent#'
</cfquery>
</cffunction>
</cfcomponent>
Create the outputNow that we've setup a query to get all the nested (child) categories, we should setup the output. We'll do this by setting text to a
output variable which will be returned. Remember, you should never need to display anything from inside your functions, it should be returned using cfreturn.
CODE
<cfcomponent name="Categories">
<cffunction name="getCats">
<!--- Parent ID --->
<cfargument name="parent" type="numeric">
<!--- Query for Children of Parent --->
<cfquery name="cats" datasource="YOUR_DATASOURCE">
SELECT * FROM categories WHERE parent = '#arguments.parent#'
</cfquery>
<!--- Create Output --->
<cfset output = "<ul>">
<!--- Loop over all items --->
<cfloop query="cats">
<cfset output = "#output# <li>#cats.name#</li>">
<!--- Check Children of this item --->
<cfif cats.recordcount GT 0>
<cfset output = "#output# #CreateObject('component', 'categories').getCats(cats.id)#">
</cfif>
</cfloop>
<cfset output = "#output#</ul>">
<cfreturn output />
</cffunction>
</cfcomponent>
We did a lot in that step, but it's really pretty simple. We've looped over the query appending text to our
output variable and using
#CreateObject('component', 'categories').getCats(cats.id)# we call the component and function from within itself to get child categories for the category the query is currently on. After the loop is finished, we return the
output variable.
Putting it on a pageSave your categories.cfc and create a new .cfm file. This is where you'll call your recursive function and display your categories in a nicely organized list.
CODE
<cfoutput>
#CreateObject('component', 'categories').getCats(0)#
</cfoutput>
We instantiate the categories component we just made and call the getCats function. When you created your table to query categories from, all of your root (top-level) categories should have a parent of 0, passing 0 to the parent argument starts at the very top of your nesting and begins to recurse down.
You should see something like this:
- Parent 1
- Child 1.1
- Child 1.2
- Child 1.2.1
- Child 1.2.1.1
- Child 1.2.1.2
- Child 1.2.1.3
- Parent 2