This week I got two simple Application.cfc questions that I thought would be interesting to write up. The first one is from Gary and asks:
In Application.cfc
<cfset this.name = "MyFancyName" />
There is also:
<cfset application.name = "MyFancyName" />
What is the difference?
Inside the Application.cfc there is a difference between what you set in the This scope versus what you set in the Application scope. The This scope, within Application.cfc, is used to setup and configure the application. Therefore, when you set this.name = "whatever", you are naming the Application globally across the server. Application.name, however, is nothing special. It is simply a value within the Application scope and does not have any impact on the behavior of the application itself.
Not to make things confusing - but when you name your application, ColdFusion copies the name to the Application scope in a key called applicationname. So given the pseudo-code above, if you dump the Application scope you would see name and applicationname as values.
Now for the second question. Ken asked:
I'm calling an application via cfmodule but I can't get it to use the application.cfc page. The structure is as follows:
webroot (folder)
index.cfm
myapp (folder {under web root folder})
application.cfc
default.cfm
index.cfm code as follows
cfmodule template="myapp/default.cfm" lhn="1"
In the application.cfc file I have session variables, one of which is lhn which I want to assign the value passed in the cfmodule tag.
But it does not seem to use the application.cfc file and thus no session exists.
Good question. It all comes down to the question of - when is Application.cfc/cfm run? The answer is only for network requests. In order for an Application.cfc to fire there must have been a network request to a resource. cfmodule (or cfinclude) will not execute a network request and therefore not execute the Application.cfc file. I hate to say it - and as soon as I type it I'm going to regret it - but you may consider using a cfhttp call to your other application to fetch the data you need. Or - update your custom tag to support running in a "non-initialized" form. Ie, the custom tag could handle noticing it doesn't have Application variables it needs and can handle setting it up itself - possibly within a subkey so as to not overwrite things in the current application. It could possibly also make use of the Server scope, which could be a handy way to handle App to App communication on a box.
Archived Comments
Thanks Ray for these two Q/A's. Your first answer brought to light something I didn't know. However I'm not sure exactly what that means. Can you provide an example of the differences? Thanks.
The differences between what? The This Scope and the Application Scope?
Yes - the this scope and the application scope.
I feel like I failed in my explanation. :) In terms of Application.cfc, the This scope expresses the _behavior_ of the Application. What's the name - what are custom tags paths - whats the common datasource name. Etc.
Application scope variables are simple name/value pairs. Application.foo = "goo". Etc. They do not impact how the application behaves at the server level. (Technically they can impact your app if your app does different things based on application variables, but I'm talking about _built in_ behavior.)
Hi Ray, I have a (dumb?) question related to this:
Back when there was no Application.cfc. only Application.cfm, there were occasions when it was proper to cfinclude – in Application.cfm – another Application.cfm that was higher up in the directory hierarchy. Can this somehow be done when using Application.cfc?
I have not been able to figure out how to do this, the result being that I have separate Application.cfc’s in different folders, but sometimes one is practically a duplicate of the other.
I hope I am making myself clear.
Ray,
For the second question about looking for a session variable within a module, would it not be a better practice to send in the session var as an attribute of the cfmodule as follows?
<cfmodule template="myapp/default.cfm" lhm="#session.lhn#">
@Bill King: If we assume that you build some custom tag API for the App, then yes, you would want to pass the session var like that. The other app cannot/should not know about your session vars.
@Carlos: App.cfc _can_ extend other App.cfcs. I know Ben Nadel just recently did a blog post on this and Sean Corfield also has. Personally - I've never really needed the functionality myself.
Thanks Ray, exactly what i was looking for.
Perhaps Ken, your second questioner, just needs to define his variable as a session or application variable (depending on variable's lifespan needs) in a root level Application.cfc. I use the extends attribute to 2 levels (its limit at least in CF8) in my main work application web portal of a couple dozen systems/applications that I help to develop/manage. It works great and I'm able to inherit or override (using 'super') the methods and properties 1 to 2 levels up as needed depending on the system. I have not tried to go in the other direction, but I suppose it would be possible. I'm not saying Ken should do it this way, but it is probably an option. I have a root level application.cfc that we'll say exists at a mapping of 'webroot'. In the first lower level folder like Ken we'll call myapp, I have an Application.cfc with <cfcomponent extends="webroot.Application" ... > . I also have an application with a subfolder we'll say called mysubapp with an Application.cfc with <cfcomponent extends="webroot.myapp.Application" ... > . Using these I'm able to reduce the duplication of methods and properties and take advantage of OO inheritance.
Here is a follow up question. Is there wa way for application A to share application variables with application B?
I would look at using cfinterface, which I have yet to need, if you are talking a 2-way transaction, which I assume. One way could be done many different ways.
Here is application.cfc
<cfset this.name = "MyFancyName" />
Here is index.cfm in the same root
<cfoutput>#this.name#</cfoutput>
Got error. I cannot convince why. So, I've tried the another way like in index.cfm
<cfoutput>#application.name#</cfoutput>
Got error also.
Sorry, Ray. I got the answer.
Another question is when I defined <cfset this.datasource = "PPShein" /> in application.cfc, how can I get this.datasource value in index.cfm?
@Ray: Thank you for your help. In the end I just needed to ensure that the session variable was defined.
@Bill King: I did pass through the lhm, but it is a hard coded value. As there is no Application.cfc (in fact there is only one cfm page) at this level there is no session scope so you can not pass through a session var.
@Brian O: This is two distinct applications, well really a base level Intranet home section. That is menu, banner footer and home page. with the home page containing the other application. It's a notice board.
On another note, the reason I used cfmodule in the first place was because using cfdiv with bind the spry dataset would not load.
Ken
@PPshein: Unfortunately, there is no way to get the datasource value set in the DSN. The whole point of that feature (normally) is to set it so you don't need it elsewhere. If you need it, I'd just set it in the app scope as well.
For Ken, aside from creating another level of application.cfc (which another poster posited), another option is to simply pass the session variable you need as an argument in the cfmodule tag. Then the myapp/default.cfm can read from the arguments struct and go from there.
That is, unless I missing something here.
@Peter Hoopes: The session variables are created when a user/admin logs into the system. Because of the nature of the system I would have to create a structure with default values and pass that through as an argument. It is easier just to check that the session vars are defined. Initially I just assumed that cfmodule would invoke the application.cfc, which I now know it will not.
Ken
Hi Ray, I have a question here,
we are on colfusion 9 but not using the Application.cfc, we are still using Application.cfm
Now the thing is we have cfmails defined everywhere and i do not know at how many places, we want to use the this.smtpserversettings feature of cf9 in application.cfm file, how will i declare this in application.cfm file
You can't do it. I'd recommend just simply switching to Application.cfc.
u mean to say simply there is no other way
if i can create application.cfc and onrequeststartmethod call my application.cfm, will that work and will it have any side effects
You should be able to. Don't forget to remove the cfapplication tag from application.cfm.
ok, so like the above i an do the <cffunction name="onrequestStart()">
<cfinclude template="application.cfm">
</cffunction>
thopugh this will not effect the sessions and other variables defined in the website
Well, sure, that may work. It really depends on whats in your file, but it may work. Again, remove the <cfapplication> tag.
@ppshein In Cf9 you can get this.datasource value in index.cfm via #application.getApplicationSettings().datasource#
"Not to make things confusing - but when you name your application, ColdFusion copies the name to the Application scope in a key called applicationname."
So I'm assuming they are not consistent about this. For example: I want to use this.secureJSON and this.secureJSONPrefix. But when I do, in my protection function which actually does the check, I cannot access application.secureJSON or application.secureJSONPrefix. So I'm going to have to create both sets of variables (this & application) and set the identically. Do you know of a better way?
If you are talking about reading application settings like this, ColdFusion added GetApplicationMetadata just for that purpose.
Just what I needed. I need to keep up with new crap like this better. You da man. Thanks!
No problem. To be fair, I think this was added in CF10, so not terribly new.