I just building an app using the noxml implementation of fusebox 5.5 to test it out in a real world situation. There doesn’t seem to be a huge amount out their about this at the moment so I thought I’d jot down my findings.
Because I use plugins quite a lot, I’ve decided to keep fusebox.xml.cfm but no longer define the circuits in it. To do this you need to add:
<parameter name="allowImplicitCircuits" value="true" />
I also prefer to keep the parsed, plugins & lexicons directory off the website root, hence:
<parameter name="parsePath" value="fb_extensions/parsed/" /> <parameter name="pluginsPath" value="fb_extensions/plugins/" /> <parameter name="lexiconPath" value="fb_extensions/lexicon/" />
If you’re new to fusebox I recommend setting the mode to “development-full-load” or “development-circuit-load” until you are more comfortable with how fusebox works. This means that the circuit files are read on each request so any changes you make will take effect.
<!-- possible values : development-full-load|development-circuit-load|production --> <parameter name="mode" value="development-circuit-load" />
I’ve left the lexicons in for now in case I decide that I need to use them in a circuit.xml.cfm later, but it is not required.
Example fusebox.xml.cfm
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fusebox>
<fusebox>
<circuits />
<parameters>
<parameter name="fuseactionVariable" value="fuseaction" />
<parameter name="defaultFuseaction" value="App.Start" />
<parameter name="password" value="skeleton" />
<!-- possible values : development-full-load|development-circuit-load|production -->
<parameter name="mode" value="production" />
<!-- no need to declare circuits -->
<parameter name="allowImplicitCircuits" value="true" />
<parameter name="strictMode" value="true" />
<parameter name="conditionalParse" value="true" />
<parameter name="scriptFileDelimiter" value="cfm" />
<parameter name="characterEncoding" value="utf-8" />
<parameter name="precedenceFormOrUrl" value="form" />
<parameter name="parsePath" value="fb_extensions/parsed/" />
<parameter name="pluginsPath" value="fb_extensions/plugins/" />
<parameter name="lexiconPath" value="fb_extensions/lexicon/" />
<parameter name="errortemplatesPath" value="fusebox5/errortemplates/" />
<!-- search engine safe parameters... -->
<parameter name="self" value="index.cfm" /> <!-- default: index.cfm -->
<parameter name="queryStringStart" value="?" /> <!-- default: ? -->
<parameter name="queryStringSeparator" value="&" /> <!-- default: & -->
<parameter name="queryStringEqual" value="=" /> <!-- default: = -->
</parameters>
<globalfuseactions>
<preprocess>
</preprocess>
<postprocess>
</postprocess>
</globalfuseactions>
<plugins>
<phase name="preProcess">
<plugin name="ErrorHandler" path="" template="errorHandler.cfm" />
<plugin name="Functions" path="" template="functions.cfm" />
</phase>
<phase name="preFuseaction">
</phase>
<phase name="postFuseaction">
</phase>
<phase name="fuseactionException">
<plugin name="ErrorFuseactionException" template="fuseactionException.cfm" path="" />
</phase>
<phase name="postProcess">
</phase>
<phase name="processError">
<plugin name="ErrorProcessError" template="ProcessError.cfm" />
</phase>
</plugins>
</fusebox>
I’m using Application.cfm instead of Application.cfc. This is purely because when I develop sites I build them all on a local intranet server in sub directories of the web root (i.e. http://localserver/myfbapp/), this also applies to the client extranet preview version. As Application.cfc extends fusebox5.Application which would need to be myfbapp.fusebox5.Application, which then breaks when you upload it to it’s own domain. A shame as I like the power of Application.cfc but for ease of rollout I’m sticking with Application.cfm. I think ANT maybe a solution to this, but we use IIS and Dreamweaver in-house, one day I’ll get Subversion and ANT up and running and persuade everyone else to switch to it!
The next issue I had was that with the XML version of Fusebox, I used to use the <prefuseaction callsuper=”true”> in a circuit.xml.cfm file to allow me to set my global xfas in a parent circuit.xml.cfm and then inherit them, which works really well if you split your app up into say admin, member, public directories. Any xfas specific to that circuit could then be set in the actual <prefuseaction>.
Example:
in Admin/Users/circuit.xml.cfm
<prefuseaction callsuper="true"> <!-- set circuit specific xfas --> <xfa name="UsersAdd" value="s_Users.Add" /> <xfa name="UsersEdit" value="s_Users.Edit" /> </prefuseaction>
in Admin/circuit.xml.cfm
<prefuseaction> <!-- set global xfas (applies to all child circuits) --> <xfa name="UsersList" value="s_Users.List" /> <xfa name="ClientsList" value="s_Clients.List" /> <xfa name="SuppliersList" value="s_Suppliers.List" /> </prefuseaction>
As the noxml version of Fusebox doesn’t have parent circuits anymore (would have been defined in fusebox.cml.cfm) I decided to create a Global.cfc which each circuit cfc extend.
Example: Global.cfc
<cfcomponent>
<cffunction name="setGlobalXfa" hint="I set up global xfa's used in the navigation">
<cfargument name="myFusebox" />
<cfargument name="event" />
<cfset event.xfa("TypesList", "Types.List") />
<cfset event.xfa("RoomsOverview", "Overview") />
</cffunction>
</cfcomponent>
Example: Users.cfc (which extends Global.cfc)
<cfcomponent extends="Global"> <cffunction name="prefuseaction" output="false"> <cfargument name="myFusebox" /> <cfargument name="event" /> <cfset super.setGlobalXfa( myFusebox=myFusebox, event=event ) /> </cffunction> </cfcomponent>
This works but I wasn’t sure it’s the best practice as it seemed a bit clunky, so I posted it to the Yahoo Fusebox 5 group (I always like to have a solution before asking a question to show that I have made some effort!)
I got this reply from Mr Guru himself, Sean Corfield:
Just add a method called prefuseaction() to your Global.cfc – then you only need the super call if a child circuit also adds prefuseaction():
Global.cfc:
function prefuseaction(myFusebox,event) {
event.xfa("TypeList","Types.List");
event.xfa("RoomsOverview","Overview");
}
Child1.cfc:
<cfcomponent extends="Global"> <cfscript> // no prefuseaction here
function myAction(myFusebox,event) {
...
}
</cfscript>
</cfcomponent>
Child2.cfc:
<cfcomponent extends="Global">
<cfscript>
function prefuseaction(myFusebox,event) {
super.prefuseaction(myFusebox,event);
...
}
function myAction(myFusebox,event) {
...
}
</cfscript>
</cfcomponent>
This does the same thing as my method, but in a much neater and more sensible way. Thanks Sean!
I’m not saying this is the way to use Fusebox without xml circuits, but my conclusions so far is that the noxml way of working looks very promising. The designers I work with always got confused by the xml and when to reload fusebox if anything changed. I’m sure they have done it when an image got cached in their browser, thinking that would help. No xml means that I have the power of cfcs, the cfcs and hence the app can self document to a large extent, and gets rid of the tedious task of defining each circuit in Fusebox.xml.cfm.
The things that I miss about the XML way is the permissions and access=”internal” attributes of circuit.xml.cfm.
Great work Fusebox team!
Really good to see more coverage of the no-XML approach. A clarification: allowImplicitFusebox is the setting that allows you to omit fusebox.xml, allowImplicitCircuits is the setting that allows you to omit circuit.xml files (so it’s sort of redundant and somewhat tautologous to have allowImplicitFusebox set true inside fusebox.xml
I generally have only one set of core files on a server with a /fusebox5 mapping – or put the core files directly under my webroot – so Application.cfc can simply extend fusebox5.Application without issue.
Mind you, if you put fusebox5/ in the same directory as your Application.cfc, the relative extends should still work.
In 5.5.1, due in a few weeks, only the controller CFC is access public – the model and view circuits are (correctly) access internal. Permissions could be handled through additional attributes on cffunction – I’ll have to think about that… ticket 324, slated for 5.6. You can also use access=”private” or access=”package” to ensure methods (fuseactions) can only be called from that CFC or from other controllers (or model or view) respectively.
Hope that helps.
Comment by Sean Corfield — February 14, 2008 @ 6:37 pm |
Thanks for the clarification Sean. Now that you’ve pointed it out is does seem a bit pointless! I had thought that the allowImplicitFusebox was what made Fusebox auto discover the circuits. I’ve used the allowImplicitCircuits since it was introduced (Fusebox 5.0?) as it was a real pain having to create blank circuit files in each Model and View directory. I’ll edit the post.
When I build apps I try to make them as portable as possible (Clients like to think they can move their site to any CF host), which is why I always include the Fusebox core files. Putting the core files in the webroot and also in the /mysite/ subfolder is a really simple solution to problem I mentioned, as it will just use whichever one is appropriate to the environment. I like it!
I have been setting the access attribute to control permissions, I left it out of the post to keep thing simple, but I think it is a good idea.
Comment by aliaspooryorik — February 15, 2008 @ 9:16 am |