now musing at www.aliaspooryorik.com!

February 20, 2008

Fusebox is self documenting!

Filed under: ColdFusion, Fusebox — aliaspooryorik @ 9:11 am

One of the interesting things about writing your Fusebox app as cfcs is that if you add the hint attribute to each function then you can create documentation for your web site.

If you’re using the traditional XML version of fusebox then look here.

<cfcomponent output="false" hint="I am the Rooms Controller Circuit.">
  <cffunction name="Update" output="false" hint="I update multiple room to a new status.">
    ...
  </cffunction>
  <cffunction name="Overview" output="false" hint="I show an overview of all rooms by status and type.">
    ...
  </cffunction>
  <cffunction name="Add" output="false" hint="I add one or more rooms for the Client.">
    ...
  </cffunction>

  <cffunction name="prefuseaction" output="false">
    <cfargument name="myFusebox" />
    <cfargument name="event" />
    <cfset super.prefuseaction(myFusebox=myFusebox, event=event) />
    ...
  </cffunction>
  <cffunction name="postfuseaction" output="true">
    <cfargument name="myFusebox" />
    <cfargument name="event" />
    <cfset super.postfuseaction(myFusebox=myFusebox, event=event) />
    ...
  </cffunction></cfcomponent>

The screen shot below shows a the auto generated documentation for the Rooms Controller circuit.

Fusebox Self Documentation Screenshot

Here’s the code I used to generate it, just put it in the Application root. I’ve highlighted the variables you may need to change. (If you are using Application.cfc then read this post on Calling non fusebox cfm templates when using Fusebox 5.5’s Application.cfc )

<cfset strControllerCircuitsPath = "controller/" />
<cfset qryCircuits = ControllerCircuits( ControllerCircuitPath=strControllerCircuitsPath ) />
<cfset lstHidefuses = "postfuseaction,prefuseaction" />
<cfoutput>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Document Fusebox Application</title>
<style type="text/css">
body{ font-family:Verdana, Arial, Helvetica, sans-serif;
  font-size:62.5%;
  line-height:1.6em;
  margin: 15px 10 20px 10px;
  padding:0;
  background-color:##FAFAFA;
  color: ##525252;

}
h1{
  font-size:1.4em;
  margin:0 0 16px 0;
  padding:0 0 5px 0;
  border-bottom:1px solid ##e7e7e7;
  color:##5e5e5e;
}
h2{
  font-size:1.2em;
  font-weight:bold;
  padding:12px 0px 2px 3px;
  margin:15px 0 8px 0px;
  border-bottom:1px solid ##e7e7e7;
  color:##5e5e5e;
  clear:both;
}

p, li, dd, dt{font-size:1.1em;}
p{ margin: 0 0 20px 0; }

/* Tables */
table {width:100%;}
caption {text-align:left; font-style:italic}
th {text-align:left; background-color:##CCCCCC}
.property {background-color:##F3F3F3; width:20%;}

ul##nav{
  margin:0px;
  padding:4px 0 4px 0px;
  list-style:none;

}

##nav li{
  display:inline;
  margin:0 2px 0 0;
  padding:0px 10px 0 0px;
  font-size:1.1em;
  float:left;
}

</style>
</head>
<body id="top">
<h1>Fusebox Controller Circuits (cfc)</h1>
<ul id="nav">
<cfloop query="qryCircuits">
  <li><a href="##circuit_#qryCircuits.name#">#qryCircuits.name#</a></li>
</cfloop>
</ul>
<cfloop query="qryCircuits">
  <h2 id="circuit_#qryCircuits.name#">#qryCircuits.name#</h2>
  <cfset sCircuitName = ReplaceNoCase(qryCircuits.name, ".cfc", "", "one") />
  <cfset oCircuit = CreateObject('component',
    Replace(strControllerCircuitsPath, "/", ".", "all") & sCircuitName) />
  <cfset oMetaData = GetMetaData(oCircuit) />
  <cfset aFunctions = oMetaData.functions />  <p>
    <strong>Name:</strong> #oMetaData.Name#<br />
    <strong>Hint:</strong> <cftry>#oMetaData.Hint#<cfcatch>[none]</cfcatch></cftry>
  </p>
  <table summary="fuses in the #qryCircuits.name# circuit">
    <caption>Fuses in the #sCircuitName# circuit</caption>
    <cfloop from="1" to="#ArrayLen(aFunctions)#" index="ndx">
      <cfif ListFindNoCase(lstHidefuses, aFunctions[ndx].name) eq 0>
      <tr>
        <th scope="col" colspan="2">
        #aFunctions[ndx].name# [#sCircuitName#.#aFunctions[ndx].name#]
        </th>
      </tr>
      <tr>
        <td class="property">hint:</td>
        <td><cftry>#aFunctions[ndx].hint#<cfcatch>[none]</cfcatch></cftry></td>
      </tr>
      <tr>
        <td class="property">description:</td>
        <td><cftry>#aFunctions[ndx].description#<cfcatch>[none]</cfcatch></cftry></td>
      </tr>
      <tr>
        <td class="property">access:</td>
        <td><cftry>#aFunctions[ndx].access#<cfcatch>[none]</cfcatch></cftry></td>
      </tr>
      <tr>
        <td class="property">output:</td>
        <td><cftry>#aFunctions[ndx].output#<cfcatch>[none]</cfcatch></cftry></td>
      </tr>
      </cfif>
    </cfloop>
  </table>
  <p><a href="##top">back to the top</a></p>
</cfloop>
</body>
</html>
</cfoutput>

<cffunction name="ControllerCircuits"
  returntype="query"
  hint="I return all the cfc's in the specified directory">
  <cfargument name="ControllerCircuitPath"
    required="true"
    hint="I am the relative path to the Controller cfc files." />
  <cfset var strFullPath = ExpandPath(Arguments.ControllerCircuitPath) />
  <cfif ReFind("(\.){2}(\/|\\)", Arguments.ControllerCircuitPath)>
    <cfthrow message="'#Arguments.ControllerCircuitPath#' invalid. You can not navigate up."
      detail="Please specify a directory beneath #GetDirectoryFromPath(GetCurrentTemplatePath())#" />
  <cfelseif DirectoryExists(strFullPath)>
    <cfdirectory action="list"
      directory="#strFullPath#"
      filter="*.cfc"
      name="qryControllerCircuits" />
  <cfelse>
    <cfthrow message="The specified directory does not exists"
      detail="directory '#strFullPath#' does not exists." />
  </cfif>
  <cfreturn qryControllerCircuits />
</cffunction>

February 18, 2008

Using Fusebox relocate with noxml

Filed under: ColdFusion, Fusebox — aliaspooryorik @ 9:40 am

relocate verb Arguments:

Name Required Type Default
url Optional string  
xfa Optional string  
addtoken Optional boolean false
type Optional string client

Example usage in Tasks.cfc:

     <cffunction name="add">
        <cfargument name="myFusebox" />
        <cfargument name="event" />

        <!--- add task to database --->
        <cfset myFusebox.do( action="time.act_addtask" ) />
 	<!--- set up xfa with parameters --->
	<cfset event.xfa( "tasklist","tasks.show", "taskId",id ) />
	<cfset myFusebox.relocate( xfa="tasklist" ) />

    </cffunction>

This will redirect to index.cfm?fuseactionvariable=tasks.show&taskId=1234

More info:

http://trac.fuseboxframework.org/fusebox/wiki/RelocateVerb

February 15, 2008

Calling non fusebox cfm templates when using Fusebox 5.5’s Application.cfc

Filed under: ColdFusion, Fusebox — aliaspooryorik @ 5:55 pm

I’ve just encountered a problem where I wanted to run a non fusebox cfm script outside of Fusebox. If you use the Application.cfc supplied with Fusebox5.5, then it will route all requests to a cfm template through Fusebox regardless of what the template is called. As no fuseaction was specified, it just loaded the start page of my Fusebox app in the browser.

For example in my webapp root I have Application.cfc, index.cfm (both as supplied in the Fusebox 5.5 download) and another script called cgi_dump.cfm which just contains <cfdump var=”#cgi#” />. Calling cgi_dump.cfm in your browser will load the fusebox app.

One solution for this would be to put my non fusebox script in a sub folder with it’s own Application.cfc or Application.cfm which works but is a bit annoying. Rather than go for the simple solution, I had to work out a way for this to happen!

My hack for this is to edit the Application.cfc and add an onRequest method:

<cffunction name="onRequest">
	<cfargument name="targetPage" type="string" required="true" />

	<cfif ListLast(arguments.targetPage, "\/") eq myFusebox.getSelf()>
		<cfset super.onRequest(arguments.targetPage) />
	<cfelse>
		<!--- Include the requested page. --->
		<cfinclude template="#arguments.targetPage#" />
	</cfif>
</cffunction>

This checks to see the name of the called template against the known fusebox ‘hub’ template (usually index.cfm). Just to make sure that myFusebox.getSelf() is set to “index.cfm” (which it won’t be if the fusebox app hasn’t been run before), then add the FUSEBOX_PARAMETER:

// force fusebox to only run if this script is called
FUSEBOX_PARAMETERS.self = "index.cfm";

To stop the Fusebox debugging, you’ll need to also add the onRequestEnd method to your Application.cfc.

<!--- not part of the Fusebox Application.cfc --->
<cffunction name="onRequestEnd">
	<cfargument name="targetPage" type="string" required="true" />

	<cfif ListLast(arguments.targetPage, "\/") eq myFusebox.getSelf()>
		<!--- Pass request to Fusebox. --->
		<cfset super.onRequestEnd(arguments.targetPage) />
	</cfif>
</cffunction>

Specifing a directory for implicitly locating circuits in Fusebox 5.5 using FUSEBOX_CALLER_PATH

Filed under: ColdFusion, Fusebox — aliaspooryorik @ 4:50 pm

An updated version of this article has been posted here:

http://www.aliaspooryorik.com/blog/

I like to build my apps so that all the Controller, Model and View circuits and inside a directory off the webroot. It just seems neater to me not having lots of folders in the webroot.

If you are using the noxml version of Fusebox 5.5, then your model view and controller circuits need to have a directory structure which complies with the Fusebox conventions. To quote from the docs:

Fusebox attempts to find a CFC that represents the circuit by looking for:

  • controller/alias.cfc [access="public"]
  • model/alias.cfc [access="internal"]
  • view/alias.cfc [access="internal"]

This means that you have to have the Controller, Model and View directories in the webroot. If like me, you like to have them in a subfolder, then you can edit the FUSEBOX_CALLER_PATH parameter to specify a directory, e.g:

FUSEBOX_CALLER_PATH = getDirectoryFromPath(getCurrentTemplatePath()) & "\my_fusebox_scripts\";

This means you can have a nice neat directory structure and have the time saving advantages of not having to declare each circuit in the fusebox.xml.cfm file (and of course reloading fusebox each time you add a circuit).

February 14, 2008

Comparing circuit.xml.cfm to circuitName.cfc in Fusebox 5.5

Filed under: ColdFusion, Fusebox — aliaspooryorik @ 2:35 pm

circuit.xml.cfm (Fusebox 4 – 5.5)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE circuit>
<circuit access="public">
	<fuseaction name="List" access="public">
		<if condition="#StructKeyExists(attributes, 'user_id')#">
			<true>
				<set name="attributes.reminder_user_id" value="#attributes.user_id#" />
			</true>
		</if>
		<include circuit="mReminders" template="actGetReminders" />
		<include circuit="vReminders" template="dspListReminders" contentvariable="content.main" />
	</fuseaction>
	<prefuseaction>
		<xfa name="Calendar" value="Calendar.Month" />
	</prefuseaction>
</circuit>

CFC as a circuit with Fusebox 5.5

<cfcomponent output="false">
	<cffunction name="List">
		<cfargument name="myFusebox" />
		<cfargument name="event" />
		<cfif event.ValueExists('user_id')>
			<cfset event.setValue("reminder_user_id", event.GetValue('user_id')) />
		</cfif>
		<cfset myFusebox.do( action="mReminders.actGetReminders" ) />
		<cfset myFusebox.do( action="vReminders.dspListReminders", contentvariable="content.main" ) />
	</cffunction>
	<cffunction name="prefuseaction">
		<cfargument name="myFusebox" />
		<cfargument name="event" />
		<cfset event.xfa("Calendar", "Calendar.Month") />
	</cffunction>
</cfcomponent>
« Previous PageNext Page »

Blog at WordPress.com.