Simpler link building in FW/1
I've posted previously on how happy the move from Fusebox to FW/1 has been for us, with the single major gap from my point of view having now been filled (creating "content variables" using the view()
method).
A much less significant deficiency in FW/1, as compared to FB, has been the need to fully qualify the action when building URLs. What do I mean by that?
Most frameworks have a convention for how URLs need to be formatted so that the right action is executed for that request. In both FB and FW/1 the default format is index.cfm?action="x.y"
where x is the circuit/controller and y is the fuseaction/method.
<a href="index.cfm?action=employees.list">List of employees</a>
You could write out the URLs in your views as above, but what if they needed to change? You might decide to hide your CF server by configuring it to respond to "index.html", or use just "a" for "action" to shorten URLs. A more likely need would be to rename the "employees" controller to "staff", or "list" to "directory". Any of those changes will mean some possibly extensive find-and-replace.
Instead it's good practice to abstract the generation of URLs so that unchanging variables can be used in view links.
Fusebox: self/a and Exit Fuseactions
In FB I would accomplish this by first defining in Application.cfc the "stem" that would apply to all URLs:
function onRequestStart( required thePage )
{
request.self = "index.cfm";
request.selfa = request.self & "?action=";
}
(Having 2 separate variables, self
and selfa
, allowed me to use just output index.cfm in cases where I didn't want a query string, such as posted forms in which the action would be in a hidden form field.)
Next, in the circuit controller I would define the appropriate circuit.action for the link using an <xfa>
— eXit FuseAction — tag.
employees circuit.xml
<fuseaction name="home">
<xfa name="list" value="list"/>
...
</fuseaction>
<fuseaction name="list">
...
</fuseaction>
Note the value of the xfa is just "list", not "employees.list". If no circuit is defined Fusebox assumes the fuseaction is within the current circuit: i.e. it is relative.
Then in the "employees.home" view, I could write the link using these variables:
<a href="#request.selfa##xfa.list#">List of employees</a>
...which would output the href as:
<a href="index.cfm?action=employees.list">List of employees</a>
FW/1: buildUrl()
In FW/1 there is no built-in equivalent to XFA, but I personally continue to use the concept by creating my own xa
struct in the Request Context to hold these values: rc.xa
.
However FW/1 does have a feature allowing you to abstract the generation of URLs in the correct format: buildUrl(). Pass it the specific action for the link and it will build the URL in the correct format.
controllers/employees.cfc
function home( rc )
{
rc.xa.list = fw().buildUrl( "employees.list" );
...
}
function list( rc )
{
...
}
...which will allow me to write the link in my view as:
<a href="#rc.xa.list#">List of employees</a>
...which would output the href as:
<a href="index.cfm?action=employees.list">List of employees</a>
In FW/1 though I've had to "fully qualify" the action as buildUrl( "employees.list" )
, instead of buildUrl( "list" )
. If I decide to rename the employees controller to "staff" then I would have to make sure I replace all of these calls to buildUrl()
.
Improved in 2.0RC
In response to a request from Rick Osborne, however, the latest version of FW/1 allows you to avoid hard-coding the current section when building URLs, so the following will now work (but note the dot separator is still required).
controllers/employees.cfc
function home( rc )
{
rc.xa.list = fw().buildUrl( ".list" );
...
}
function list( rc )
{
...
}
A bit less code and more importantly less work should I rename my controller.
Comments