I need a reality check - and hopefully an explanation (if my reality is wrong).
The way the CF application framework evaluates things is this (my understanding) - re
There's two things at play here: when code runs, and when variable scopes are availed and how long they last.
Scopes:
this.name
, this.datasource
, etc). Those special-meaning variables can be changed per session or per request in the relevant handlers, but seem to apply to the entire system (ie: not for the specific session or request making the setting change). In normal CFCs, the this
scope is used to expose public variables, but as there is no public instance of Application.cfc, there is no point using the this
scope beyond making those special settings. If one wants to have variables available to all methods within the CFC, use the variables scope as one normally would. Contrary to someone's advice here, this-scoped variables are NOT the same as application-scoped variables.this.name
setting is made. Only becomes available in onApplicationStart() and thenceforth from there.
I've demonstrated this in a blog post (test code provided), over here. it's too lengthy to include here, but the stuff above summarises it.
The ColdFusion Application.cfc documentation has this tidbit of knowledge:
When a request executes, ColdFusion runs the CFC methods in the following order:
- onApplicationStart (if not run before for this application)
- onSessionStart (if not run before for this session)
- onRequestStart
- onRequest/onCFCRequest
- onRequestEnd
The onApplicationEnd, onSessionEnd, and onError CFCs are triggered by specific events.
The overall request order has (at least) two more steps.
0: execute all code in
cfcomponent
that isn't in acffunction
0.5: run the equivalent of thecfapplication
tag for creating the Application
As such the answers to your questions are:
this
scope, but will not take effect in step 0.5.Please see the comments as it would appear the below post works but it does not. If you dump the this scope, your new value is displayed, but it does not actually change any application settings.
You can change any of the application settings anywhere you like; however, because the pseudo constructor runs each time a page is requested you will need to constantly change the setting after the pseudo constructor runs. The application scope is not available in the pseudo constructor so you can do this in the onRequestStart or onRequest function. I have done a simple test reassigning the customtagpaths per a condition in the onRequestStart function. You will notice the first time you access the page the custom tags folder will be 'customtags' additional requests will indicate 'someOtherCustomtagsFolder' On a side note if your application settings change on a per-user basis your global application settings will be flip-flopping and could cause problems with other users getting incorrect settings.
<cfcomponent>
<!--- pseudo constructor --->
<cfset this.customtagpaths = expandPath('./customtags')>
<!--- onRequestStart --->
<cffunction name = "onRequestStart" returnType="void">
<cfif structKeyExists(application,'testSetting')>
<cfset this.customtagpaths = expandPath('./someOtherCustomtagsFolder')>
</cfif>
</cffunction>
<!--- onRequest --->
<cffunction name = "onRequest" returntype="void">
<cfargument name="targetPage" type="String" required = "true" />
<cfdump var = "#this#" label = "this">
<cfset application.testSetting = "foo">
<cfinclude template="#Arguments.targetPage#">
</cffunction>
</cfcomponent>
Anything in the this scope inside an Application.cfc file becomes an application varialbe and is only created ONCE per application life cycle. After the application starts, there is no other user for this within Application.cfc.
The first time a CF application is run, the contents of onApplicationStart() are run before onRequest/Start/End (with the exception of the "new in CF10" onServerStart()).
Any application variables set anywhere in the application exist until the application is stopped.
Your code from #3 should just be
if ( !structKeyExists( application, "myvar" ) { application.myvar = foo; }
then reference application.myvar wherever you need it.
From your description, nothing needs to be added to the this scope, it just needs to be put in the application scope.
the application scope is not available in the Application.cfc pseudo constructor, because until this.name has been set there is no way to tie the request to the application.
If you are worried about the overhead of creating your apps mappings, one approach would be to cache them in the server scope which is available.
if(!structkeyexists(server, 'myappmappings')){ server.myappmappings = createMappings(); } this.mappings = server.myappmappings;
you might also be able to use cachePut/cache Get to store the mappings in ehcache, but I've not tried that in the pseudo constructor.