How to intercept and replace fuseaction content in Application.cfc? - coldfusion

I use Coldfusion 9, fusebox 3 and an Application.cfc in my web application.
I would like to control, intercept and eventually change the value of fuseaction in the onRequestStart section of the Application.cfc
I'm able to check the content of the fuseaction ( with a single ListFirst(fuseaction, ".")) but I have tried to replace the fuseaction value without success.
Should I need to absolutely use a and rebuild my URL or is there another solution ?
What is the best solution ?
Thanks.

Related

How to call OnRequestStart from Application.cfm

I am a new to ColdFusion. I have Application.cfm and would like to add an onRequestStart function, but it is not working. By not working I mean, when a page calls some application variables (that were set inside `onRequestStart) an error is generated because those variable don't exist.
I can't use Application.cfc. Is there a solution or another way to use onRequestStart with Applciation.cfm?
So I'm not really sure what your trying to do with the Application.cfm, but like Ageax said, the Application.cfm runs on every request ( whatever workflow you had in mind for the onRequestStart() function you can just do in the Application.cfm)
If you really want an onRequestStart function in Application.cfm you can make your own function and explicitly call it after like this
Application.cfm
<cfset Application.test = " AND IS USING AN Application Var :D!! ">
<cfscript>
function onRequestStart(){
RETURN "THIS HAPPENS AT THE START OF EVERY REQUEST! #Application.test#";
}
</cfscript>
<cfoutput> #onRequestStart()# </cfoutput>
This question and article might be an intresting read for you if your not forced to use an Application.cfm
ColdFusion: Are there any use cases where an Application.cfm is preferable to an Application.cfc
Migrating from Application.cfm to Application.cfc
If you need to using Application.cfm (not sure why this would be a requirement as Application.cfc has been around a very long time), it handles the basic onRequestStart functionality and is loaded before every *.cfm file.
You can add onRequestEnd functionality by creating a OnRequestEnd.cfm file.
Better reference: Coldfusion using onRequestEnd() with Application.cfm files
Please add requestStart.cfm file to you project, put your code in this file. It will run on every request (start).

Do custom tags in application.cfc ignore this.customTagPaths?

Within my root application.cfc I define this.customTagPaths. This is verified to work on all pages, including those in subfolders. Within one subfolder I have an application.cfc that extends this root application.cfc. Pages within this folder still use the correct custom tags so we know that this is working correctly.
However, when trying to use a custom tag within the [subfolder]/application.cfc file itself I believe it is pulling from a different custom tag path. I added some debug information into the custom tag and it outputs when the custom tag is called from a normal page, but does not output when called from the application.cfc. I do not have access to the server to put debugging information in the other custom tag paths to be sure.
Does code in the application.cfc ignore this.customTagPaths and, if so, how do I use the specific tag I need? This custom tag sets a variable in the caller scope, so it cannot be called with a simple cfInclude.
Edit
I will attempt to address some of the questions in the comments here.
The custom tag in question has been simplified down to this code:
<cfset Caller.groupList = "">
<cfquery name="getGroups">
SELECT id, name
FROM groups
WHERE id = 1
</cfquery>
<cfoutput query="getGroups">
<cfset Caller.groupList = #ListAppend(Caller.groupList, name)#>
</cfoutput>
<cfoutput>Caller.groupList: #Caller.groupList#<br></cfoutput>
The Application.cfc is using this code:
<cfcomponent extends="RootApplication">
............
<cf_groupList>
<cfoutput>request.groupList: #request.groupList#<br><br></cfoutput>
</cfcomponent>
When cf_groupList is called directly from a cfm it writes "Call.groupList: xxxx" out to the page and shows the correct values from the dev database. However, when the Application.cfc runs the custom tag "Call.groupList: xxxx" never appears, but "request.groupList: xxxx" does, and in the latter case it shows the list that we would expect from the live database. Both the live and dev sites are currently on the same server, which we are in the process of changing, but for now I have no debugging information.
The reason I am calling a custom tag from Application.cfc is because this tag is used many other places. Simply copying and pasting the code into Application.cfc would solve the problem, but then we have an issue of duplicated code that we need to remember to update in two places in the future. Using the custom tag in the application.cfc instead of duplicating code seemed like the correct approach.
Mark, you are correct. When placed in the parent Application.cfc the custom tag works correctly. In the child it does not.

How to get directory path up to a specific folder only?

Using: CF10 and IIS7.5
I have a section within my website called "Bookings". It is located like this:
c:\inetpub\wwwroot\mysite\bookings
Within this folder will be sub-folders and eventually webpages themselves. Heres an example:
c:\inetpub\wwwroot\mysite\bookings\holidays\new.cfm
c:\inetpub\wwwroot\mysite\bookings\carhire\edit.cfm
I include (using <cfinclude>) another page within each webpage that displays different links depending on which page is calling it. All I want to know is the directory up to the "bookings" folder. Something like this (pseudo code):
<cfset whereAmI = #GetDirectoryFromPath(GetBaseTemplatePath())#>
<cfif #whereAmI# EQ "C:\inetpub\wwwroot\mysite\bookings">
<h1>Booking Section Links</h1>
</cfif>
The above code works only if the user visits the bookings/index.cfm page of the "bookings" folder. But if they go to the bookings/holidays/new.cfm page, it is now in the holidays folder so the <h1> content will not appear. I really only want to check for any page that is in the bookings folder, even if it is within a subfolder within the bookings folder. A bit like in SQL where I could say IF #GetDirectoryFromPath(GetBaseTemplatePath())# LIKE 'c:\inetpub\wwwroot\mysite\bookings%' so it has a wildcard on the end.
I know this question is going to irritate the MVC framework advocates but please excuse me on this!
Here is a quick, easy way to solve your problem (may not work as system expands - but should get you started down the right path).
<cfset whereAmI = GetDirectoryFromPath(GetBaseTemplatePath())>
<cfif whereAmI CONTAINS "C:\inetpub\wwwroot\mysite\bookings">
<h1>Booking Section Links</h1>
</cfif>
Note, I removed the # from inside the cfset and cfif you do not need them there.
You could even scale back the path to use just 'mysite\bookings'.
Ideally, this should be wrapped up into a function so that you can easily pass different paths into it to determine if you are on a given page. Or, possibly, even determine the 'parent' folder in onRequestStart in Application.cfc and set it as a request scope variable.
This will need to be tweaked if you run the code on a *nix based system.
It is more easier with CGI variables. You can use "CF_TEMPLATE_PATH". Try this
<cfoutput>The value of CF_TEMPLATE_PATH is: </cfoutput><cfdump var="#CF_TEMPLATE_PATH#">

Must one use an MVC FrameW to produce clean URL's?

The host that I want to host with does not support server side url rewriting, thus no third party tools can be installed to rewrite the url's.
This is Coldfusion 8, on windows, IIS.
The other alternative that I know of is to use a framework, but I do not feel like taking that route (time), for the application works well as it is (but the URL).
Can clean urls be generated by purely CF?
I do not need the clean url's for seo, rather it will be for the user's easy reference to their page. E.g. youtube.com/userpage
Any sugessions?
If the only choice is to use a framework, then which one is most compatible with traditional cfml'', cfm's & CFC's? In that there needs to be minimum changes to the code in the conversion from the none frameworked app to become frameworked.
Thanks for you contributions!
No. you do not need a framework or URL rewriter to get http://domain.com/some/url to work (notice no index.cfm).
In IIS you can set up custom error pages for 404 errors. Make the custom error page execute a ColdFusion page on your server (/urlhandler.cfm, 404.cfm or index.cfm for example). Within that page, you can control your own routes with ColdFusion by using list methods on the cgi.query_string value. IIS will provide you a url that looks something like 404;http://domain.com/the/original/url which you can parse to route the visitor to your desired event.
<!--- Get URL String --->
<cfset CurrentURL = ListGetAt(cgi.query_string, 2, ";")>
<cfset CurrentURL = Replace(CurrentURL, ":80", "")>
<cfset CurrentURL = Replace(CurrentURL, ":443", "")>
<cfset CurrentURL = Replace(CurrentURL, "403;", "")>
<cfset CurrentURL = Replace(CurrentURL, "'", "", "ALL")>
We have a site that receives approx a million visitors a month that is still running SES urls with this method. I was shocked when I was hired and found this existing code at the heart of the site and would not elect to repeat it, but, if you have limitations on installing a rewriter or third party framework (this client placed restrictions on the site) this solution may work for you.
By playing with the above code, you can quickly see how you may use CF to dynamically include the .CFM file you want or execute the right CFC code depending on your set up.
You can use the Framework/1 framework or CFWheels to achieve clean URL's but it will need to include the "/index.cfm/" at the beginning of the URL in order to trigger ColdFusion's application handler code.
EDIT: Please see Aaron Greenlee's work around to prevent the "index.cfm" from appearing in the URL.
i.e. Whichever approach you take, if you cannot add a 3rd party tool to rewrite URLs (and not using Apache), your URL's will be in the form of http://site.com/index.cfm/section/item
eg.
http://site.com/index.cfm/user/login
http://site.cfm/index.cfm/user/signup
FW/1 offers the option of passing in URL variables in a search engine friendly format as well.
Examples:
http://site.com/index.cfm/user/login/email/me#you.com/password/test
is the same as
http://site.com/index.cfm/user/login?email=me#you.com&password=test
is the same as
http://site.com/index.cfm?action=user.login&email=me#you.com&password=test
Go ahead and learn a framework. Most will work for this. However if you just do not want to learn a framework.
www.mysite.com/products/
will run:
www.mysite.com/products/index.cfm
www.mysite.com/products/books
will run:
www.mysite.com/products/books/index.cfm
Framework/1 and CFZen will work for this a they are very simple 1 file frameworks that you can just work around.
CFZen
http://cfzen.riaforge.org
http://cftipsplus.com/blog/?tag=cfzen
Framework/1
http://fw1.riaforge.org
http://corfield.org - the author of Framework/1
Instead of using http://yoursite.com/index.cfm/user, you can do http://yoursite.com/user.cfm and catch the error in the OnMissingTemplate function of application.cfc. This will not require you to set a custom 404 page.

Fusebox installation without access to webroot

Previously (and locally) I've placed the fusebox5 directory in the web root, and then applications from anywhere in the tree have been able to access it. I'd previously also used Application.cfm rather than .cfc.
In this environment I don't have access to the webroot and the FB files don't really need to be that far down anyway, so I had planned to store them alongside the applications. Am I right in thinking that index.cfm is overlooked if Application.cfc is in use (and therefore there's no point changing the cfinclude value to be eg. ../fusebox5/)? If so, how can I include the framework without having Fusebox in the root or in a mapping? Error is:
Could not find the ColdFusion Component or Interface fusebox5.Application.
No, your app is still going to need index.cfm. What you'll need is a cf application mapping for Fusebox in your Application.cfc. Look at Ray Camden's Application.cfc template for an example of setting application specific mappings.
You can run Fusebox 5+ in a subfolder of your app root. It just may not be the most obvious thing to make it work.
Unfortunately, you cannot create a dynamic mapping for extending Application.cfc because your Application.cfc has not yet been instantiated - you get a chicken vs. egg scenario. You can't create the mapping to Fusebox because your Application.cfc didn't start, you can't start your Application.cfc because it can't find the component it's supposed to extend.
THIS IS A BUG IN COLDFUSION 8. ColdFusion should look for mappings in this order:
Mapped folders from the CF Administrator
Sub directories off the current directory
Sub directories off the web root called
It does this when you use CreateObject(), but not when you use the Extends attribute on cfcomponent.
The easiest solution is to use your Application.cfc like you would for any application, then include fusebox from your index.cfm. Your folder structure would look like this:
/myapp/fusebox5/
/myapp/index.cfm
-- consists of <cfinclude template="fusebox5/fusebox5.cfm" />
Your index.cfm file will not be ignored as long as you don't intercept the request with Application.cfc's OnRequest, or if you use OnRequest, make sure you include the intended target (which will almost always be index.cfm anyway).
If you want to not require index.cfm to do the include, you can have your Application.cfc's OnRequest method do the cfinclude.
<cffunction name="onRequest">
<cfinclude template="fusebox5/fusebox5.cfm">
</cffunction>
You still may need an index.cfm so your web server won't give a directory listing or 404, but it's ok if the file is empty.
In Application.cfc:
<cfscript>
this.mappings = {}; //create a new structure to store app-specific mappings
this.mappings["Fusebox"] = expandPath('./Fusebox'); //add mapping
</cfscript>