Just a quick note before I dive into this question. I've noticed lately I've been getting a few questions that cover stuff that I've answered before. I have no problems answering them again. Sometimes they cover things that really need repeating. I'm just commenting here as it seems like it has occurred a bit often lately, and if my readers are getting a bit miffed, I wanted to explain why. (As another FYI, I plan on running a survey like Todd is doing so you will have the opportunity to tell me exactly what you think of my blog.) Ok, on with the questions!
Tony asks:
Congratulations on moving to Application.cfc. You won't regret it. What you want to use is the onApplicationStart method. It is run when your application starts and is the proper place for initialization code. Please see this specific blog post for more information: Application.cfc Methods and Example UsesQuestion 1 of 2: I am now transitioning into using Application.cfc (I know...I know...but better late than never) and am not terribly sure what to do with my CFC instances. To be totally honest, I'm trying to pretty much update ALL of my CF bad habits into any and all best practices that I can. So, up til now I've been invoking components where needed and that, of course, is not terribly great practice. What I want to do is create them in Application.cfc so I can just refer to them when needed sitewide. This, I know, is no new concept. I just need assistance with getting started with it.
Which function within Application.cfc would be the best place to add createObject() reference? Can you clear this up for me? You have many posts that deal with Application.cfc issues, but I haven't tracked down the answer to my question so I thought I'd contact you directly.
I normally just use cfinclude for master header and footer files (and additional function libraries). If I'm not using Model-Glue (or other framework) specifically, what is considered a good practice as far master templates are concerned? Or is it still ok to use cfinclude for master container files as long as CFCs are being leveraged correctly?
I think you have two questions here. Should I use cfincludes for layout and should I use a cfinclude for 'master libraries' (of UDFs I assume). Let's cover layout. I don't like using cfinclude for layout. Mainly because variables will leak in between them and for sites with complex layout, it is better to have some separation. Normally I recommend custom tags. See this article: ColdFusion custom tag for layout example.
As for UDF libraries, I don't have a firm idea yet of what I consider best. You can easily do a cfinclude in your Application.cfc onRequestStart function. However, this will not place the UDFs in your variables scope. You can do this in onRequest, but onRequest has negative side effects. What I do sometimes is this - I include the library in onRequestStart, but the UDF declarations are copied to the request scope. So my UDF file may look like so:
<cfscript>
function parisIQ() { return 0; }
request.parisIQ = parisIQ;
function britneyIQ() { return -10; }
request.britneyIQ = britneyIQ;
</cfscript>
Basically I just copy the UDFs into the request scope and then reference them as request.parisIQ() or request.britneyIQ(). This also had the side effect of making them easily available in custom tags as well.
Archived Comments
Occasionally I'll just wrap all my random/util type UDF's into a CFC and throw that in the application scope like any other CFC.
Ditto Todd. I'll call it utils.cfc, and place it in the app scope for front end views that need it, and send a copy to CFCs that need it.
On reflection, I think that's kind of better - cuz sometimes you need those simple UDFs in CFCs.
Maybe. Still on the fence I guess. ;)
Thank you so much for answering my questions (and so quickly too)! Those answers helped a great deal...I appreciate it. I actually did end up finding the custom tag article you referenced just after I sent my initial questions, so I apologize for the repeats.
Thanks again!
Tony
Thanks for the additional input. I'll definitely test out both methods to discover what I prefer.
Are there specific situations I should consider where one should consider one method over the other, or is it more a preference approach?
Thanks again!
Tony
In Todd's way, if a CFC needs the methods, it has access to it. You can pass the CFC into the other CFC. In my way, it wouldn't quite work. Technically a CFC method can use the Request scope, just like any other CF file, but you don't want to break encapsulation.
@Ray-- while I also use the technique of using a custom tag to provide a layout "wrapper" for web pages, I have includes inside of the custom tag which call much of the layout (e.g. header and footer). The reason I don't include the layout code in the custom tag is to try to separate logic from presentation.
While I don't typically push frameworks, I've been thus far impressed with Coldbox's layout features. I was easily able to transition a project I had started some time ago to ColdBox and take advantage of that feature, also using pure CSS layouts. Here's a rundown on the layout stuff, specifically:
TinyURL (Preview-style):
http://preview.tinyurl.com/...
Coldbox primary setup can be found here:
http://www.ColdboxFramework...
Neat stuff, gotta tell you. One of my former bosses, Rob Gonda, is in on the project. But Luis is the brains behind it, and it's pretty snappy for me, thus far.
And, honestly, I will *never* do a project again without Coldspring. I am a Coldspring fanboy, no doubt.
- Will B.
:gasp!: Britney's IQ lower than Paris'? I'm sad. Britney will always have a soft spot in my heart, no matter how crazy she is. Lol! :-)
Ray,
I am another person converting, better late then never. In application.cfm, I have always reset path structure in every directory with an application.cfm. Then refered to the balance of the applation with an include of the main application.cfm. What is the cleanest way to handle this?
Matt
Matt, can you describe again what you are doing? I don't quite get it.
In my old application.cfm I would have variables like:
<cfset adminbase="../">
<cfset basepath="../../">
Then of course as you go deeper into the site I would reset paths in the the application.cfm with a <cfinclude template="application.cfm" above the resets, to reflect the correct path back to these locations. How would I do this with application.cfc?
Um, well, if I get you right, you want to know what the base path of your current application. You can use this in your onApplicaitionStart:
<cfset application.basepath = getDirectoryFromPath(getCurrentTemplatePath())>
That gives me a basis to start..thanks for the great article...Great stuff!
Hi Ray,
Just wanted to check in on the issue of instantiating my model cfc's in Application.cfc.
I try what you suggested in terms of setting it in the onApplicationStart method of Application.cfc as such:
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfset application.dsn = "myDSN" />
<cfset application.userModel = createObject("component", "path.to.cfc.users") />
<cfreturn true>
</cffunction>
Then in my view template, I set a local variable to use the query from this model, for example:
<cfset qry = application.userModel.getUsers() />
<cfoutput query="qry">#output code here#</cfoutput>
But this throws an error when I call the query to display results.
However, when I use the createObject() method to set it up directly in the template instead of Application.cfc (I did this just to test what would happen) it works fine. Obviously though I do not want to instantiate the model in my view template, I want to set it in Application.cfc. The site I'm working on is in my wwwroot folder, and I'm 99.9% certain I'm using the correct dot path to my cfc (unless I'm still missing something).
Any ideas what might be happening? If you need additional code to see or clarification, just let me know.
Thank you!
- Tony
The question is - what error is occurring?
Yes...the error...of course (sorry about that!)
Well, funny...now it is actually working. I'm on a different computer now, but set everything up the exact same way (as far as I can tell) and now it works as initially expected.
However, the error I was receiving last night was:
"Element USERMODEL is undefined in a Java object of type class [Ljava.lang.String; referenced as..." (etc)
I'm not sure what I missed from my set up last night and how I set it up today on another machine (which is almost identical in all respects). My guess is that I simply missed something in my Application.cfc file last night.
I'll copy the working version I have now and will bring it home for comparison to further investigate on my own.
Thanks!
-Tony
I can tell you exactly what you did. I bet you modified your app.cfc AFTER you had run your code once. Your app was already loaded, so CF didn't rerun onApplicationStart. There are 3 simple ways around that.
1) Rename your application: <cfset this.name = "something new">
I don't like doing that as I like my names to make sense.
2) Restart CF. That's a bit slow though. And it's like using a flame thrower to kill a roach.
3) Add code to onRequestStart that does:
<cfif isDefined("url.reinit")><cfset onApplicationStart()></cfif>
THen you just go to your site and add ?reinit=rayrocks to the URL. This will then rerun your onApplicationStart code.
Ah! I remember another developer explaining the re-init approach (option #3 on your list) some time ago now that you bring it up. I will definitely implement that approach.
I realize this is basic stuff...I'm just trying to get ramped up as quickly as possible to get out of all my old bad habits and hacks.
Thanks again for all your help on this!
-Tony
I hate bugging you about this one again, especially after it all seemed to be working fine for a bit.
It seems now whenever I make a change to my Application.cfc file, the same errors keep coming back. Either I get:
"Element USERMODEL is undefined in a Java object of type class [Ljava.lang.String; referenced as..." (etc)
...or I get:
"Could not find the ColdFusion Component..." (and I haven't moved any files or directories since it was working fine)
A couple of times just renaming the app (this.name) helped, but then the error got triggered again.
Per your suggestion, I added the following in my App.cfc as well:
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfif isDefined("url.reinit")><cfset onApplicationStart() /></cfif>
<cfreturn true />
</cffunction>
...and then I trigger that through the url as ?reinit=true
That helped once or twice but now it seems nothing is resetting the app for me.
I then took the flamethrower to the roach...to no avail.
Is there something that will keep from the App.cfc settings getting cached? It seems to happen so often I must have a setting wrong or something.
Thanks!
Tony
In case the question comes up, I will also note that I changed my application timeout setting to a minute during the development phase:
<cfset this.applicationTimeout = createTimeSpan(0,0,1,0) />
...to see if that would help. Nothing though.
Tony
Well, it sounds like multiple issues there. Let's focus on one. What is the exact issue right now?
I may have spoken too soon. It seems once I changed the applicationtimeout time (and after I reset a couple other things...restarted CF server, did a reinit again) NOW it seems to be behaving consistently.
Thanks!
Tony