5

I am using ColdFusion 9.0.1

I am taking over a site and the guy before me created about 100 variables and put them into the APPLICATION scope. I believe that his 100 variables were continuously being overwritten with each page load.

Basically, he had this in Application.cfc:

APPLICTION.VariableOne = "SomeStringOne";
APPLICTION.VariableTwo = "SomeStringTwo";
APPLICTION.VariableThree = "SomeStringThree";

My plan is to keep it simple and yet very readable is to test for a specific structure in the application scope. If it's not there, create the structure and variables:

if (not isDefined("APPLICTION.AppInfo") or not isStruct(APPLICTION.AppInfo)) {
    APPLICTION.AppInfo = structNew();
    APPLICTION.AppInfo.VariableOne = "SomeStringOne";
    APPLICTION.AppInfo.VariableTwo = "SomeStringTwo";
    APPLICTION.AppInfo.VariableThree = "SomeStringThree";
}

Of course, once the site is live and we are done creating all of the application variables, I'd move this into the into the onApplicationStart() method.

The solution that I want has to be more about "readability" and less about "efficiency". Several non-CFers, but very experience coders will be using this and will need to "get it" quickly.

Does my plan have any gaping holes or is it too inefficient?

Is there a more readable way of creating and managing application variables?

James A Mohler
  • 11,060
  • 15
  • 46
  • 72
Evik James
  • 10,335
  • 18
  • 71
  • 122
  • You can safely rewrite "if (not isDefined("APPLICTION.AppInfo") or not isStruct(APPLICTION.AppInfo))" as "if (NOT StructKeyExists(APPLICATION, 'AppInfo')) – Shawn Holmes Nov 29 '11 at 07:05
  • Erm there is the gaping hole of spelling APPLICATION incorrectly but I'm guessing you typed it once then copy and pasted it ;) – Kristian82 Nov 29 '11 at 16:15

3 Answers3

5

Why not move the definition into onApplicationStart() right now? If you need to reset them during development, you could always pass in a URL variable to flag it for reset, like so:

<!--- in Application.cfc --->

<cffunction name="onRequestStart">
<cfif IsDefined("url.resetApp")>
  <cfset ApplicationStop()>
  <cfabort><!--- or, if you like, <cflocation url="index.cfm"> --->
</cfif>
</cffunction>
Jake Feasel
  • 16,785
  • 5
  • 53
  • 66
  • So, my code above looks good, but you recommend putting it into onApplicationStart() now? That makes sense, especially with the URL reset. – Evik James Nov 28 '11 at 21:02
  • Well, your above code would no longer need the conditional check for the isDefined("APPLICTION.AppInfo") etc..., simply keep the variable assignment. This is because that will only run when the application starts, so there is no need to check if it already exists at that point. – Jake Feasel Nov 28 '11 at 21:06
  • If that's true, then there's really no need to put the APPLICATION variables into a structure either, right? Unless of course I want to dump them or kill them. – Evik James Nov 28 '11 at 21:11
  • Yes, you don't really need that AppInfo structure. – Jake Feasel Nov 28 '11 at 21:45
1

I would go ahead and just use OnApplicationStart but back in the pre Application.cfc days we used to do something like Application.Build and if the Build value was different then we did all of our sets on Application variables. So quick and dirty would be something like:

<cfparam name="Application.Build" default="" />

<cfset Build = "28-Nov-2011" />

<cfif Application.Build IS NOT Variables.Build OR StructKeyExists(URL, "Rebuild")>
 <cfset Application.Build = Variables.Build />
 <!--- A bunch of other CFSETs --->
</cfif>

This method though was something we used back when all we had was the Application.cfm

Snipe656
  • 845
  • 7
  • 15
1

Actually, after re-reading the OP, and reading the suggested solutions, I'm going to have to agree with the OP on his setup, for this very important reason:

This, in onApplicationStart()

APPLICTION.AppInfo = structNew();
APPLICTION.AppInfo.VariableOne = "SomeStringOne";
APPLICTION.AppInfo.VariableTwo = "SomeStringTwo";

Can then later be turned into this, within onRequestStart()

<cflock name="tmp" type="readonly" timeout="15">
   <cfset REQUEST.AppInfo = APPLICATION.AppInfo />
</cflock>

Your app can then go on to access the REQUEST vars conveniently, esp, if you decide you want to cache CFCs in the same scope--they would simply go into a separate key:

   APPLICATION.Model.MyObject = CreateObject('component','myobject');

Which, of course, also gets poured into REQUEST (if you choose)

Want to go Jake Feasel's route above? No problem:

   <cfif isDefined('URL.reload')>
      <cfset APPLICATION.Model = StructNew() />
   </cfif>

Now you're able to flexibly kill your object cache but maintain your vars (or vice versa as you choose).

This is a great setup for another reason: If you want to build in your own Development/Production "mode", in which the development mode always recompiles the CFCs, but the production mode keeps them cached. The only change you have to make on top of this, is the REQUEST set noted above:

<cfif (isProduction)>
    <cflock name="tmp" type="readonly" timeout="15">
       <cfset REQUEST.AppInfo = APPLICATION.AppInfo />
    </cflock>
<cfelse>
   <cfset REQUEST.AppInfo = StructNew() />
   <cfset REQUEST.AppInfo.VariableOne = "SomeStringOne" />
   ...etc...
</cfif>

You can also make the setting of vars and the creation of objects into a private method within Application.cfc, for even further convenience.

Community
  • 1
  • 1
Shawn Holmes
  • 3,752
  • 22
  • 25
  • Shawn, can you explain this: "Your app can then go on to access the REQUEST vars conveniently, esp, if you decide you want to cache CFCs in the same scope--they would simply go into a separate key:" What exactly do you mean by "access the REQUEST vars conveniently"? – Evik James Nov 30 '11 at 15:07
  • It means that you've done a single, safe readonly lock in onRequestStart() and brought your previously set-up APPLICATION scope vars into the REQUEST scope, where (within the remainder of your code) you are free to make calls like without having to make additional locks and worry about concurrency issues. It is a neat, single point of conversion, and works in both development and production environments (if you move forward with the methodology I describe above); works well for other shared scopes (ie SESSION), too. Hope that clarifies. – Shawn Holmes Nov 30 '11 at 15:18
  • Shawn, this was a big help. I have found most of this info before, but never together at the same time. Thanks for taking the time to provide such great examples. I really appreciate it. – Evik James Dec 19 '11 at 23:18