tags:

views:

61

answers:

4

I simply want to define a function in application.cfc and expose it application wide to all requests. Preferably the "assignment" would only happen on application startup.

Is the preferred method to do something along the lines of this:

<CFCOMPONENT OUTPUT="FALSE">
<CFSET this.name = "Website">
<CFSET this.clientManagement = true>
<CFSET this.SessionManagement = true>

<CFFUNCTION NAME="GetProperty" OUTPUT="False">
    <CFARGUMENT NAME="Property">

    <CFRETURN this.Props[Property]>
</CFFUNCTION>

<CFFUNCTION NAME="OnApplicationStart" OUTPUT="FALSE">
    <CFSET Application.GetProperty = GetProperty>
.
.
.

or is there something better?

+2  A: 

By default, GetProperty will be visible in Variables scope already, this can be sufficient for many usages (in .cfm templates).

If you want to use these methods directly in the components, referencing them in the Application scope is fine.

Though I do this with Request scope in the onRequestStart(), it's just my personal preference. Something like this:

request.udf = {};
request.udf.halt = halt;

Please note that best practice in general is incapsulating the objects and having them referenced in variables scope of the host object. I typically do this when initializing the object, simply pass previously created objects as init() arguments.

P.S. Nowadays it is recommended to use lower case for tags and their attributes. Kind of good coding practices.

Sergii
We are using onRequestStart which, I believe, does not automatically put the function in the variables scope.
Tom Hubbard
If you mean my first sentence, CF does this by default, simply because you have created the method in Application.cfc
Sergii
This link explains what I was saying. Essentially the calling cfm will only have the functions in the variable scope if you use the onRequest method because it uses cfinclude: http://www.bennadel.com/blog/805-ColdFUsion-Application-cfc-OnRequest-Creates-A-Component-Mixin.htm
Tom Hubbard
A: 

You might consider creating a seperate "properties" CFC and instanciating it as a singleton in the SERVER scope then it will be available from any CFML page even if it isn't part of an application. If you go this route then there is no "server start" event to bind to. Instead you can put this in the contructor of application.cfc or in the body of application.cfm

    <cfif not structkeyexists(server,"properties")>
        <cflock name ="loadProperties"
            timeout ="10"
            type ="exclusive"
        >
            <cfif not structkeyexists(server,"properties")>

                <cfset server.properties = 
                    createObject("component","path-to-props.cfc")
                    .init({..inital properties..})
                >
            </cfif>
        </cflock>
    </cfif>

The lock code is to prevent the overhead of creating and assigning the UDF on every request. This also allows the properties instance to persist so that having a properties.SetProperty() function will work

Mark Porter
+2  A: 

The best way to store site specific config data is probably going to be to create a new component named something such as SiteConfig.cfc with methods such as getProperty(propertyName) and setProperty(propertyName, value). You would then store this CFC in the application scope by doing the following inside Application.cfc's onApplicationStart method like:

<cfset application.siteConfig = createObject("component", "SiteConfig").init() />

Back to your original question though about storing a UDF in the Application scope, below is a way to do that. The basis is that in onApplicationStart you will create a new application persisted struct with your site's config properties like siteName and whatever else. Then a function is stored in a CFM file which is cfincluded only in onApplicationStart, then copied into the application scope. This means that all your regular page CFM files can use application.getProperty(propertyName). Since the function is only created once and stored in the application scope it satisfies your original question's requirements about "assignment would only happen on application startup".

Hope this helps a bit!

getProperty.function.cfm

<cffunction name="getProperty" output="false">
    <cfargument name="propertyName" type="string" required="true" />
    <cfreturn application.config[propertyName] />
</cffunction>

Application.cfc

<cffunction name="onApplicationStart" output="false">
 <cfset application.config = structNew() />
 <cfset application.config.siteName = "My App's Display Name" />
 <cfinclude template="getProperty.function.cfm" />
 <cfset application.getProperty = variables.getProperty />
</cffunction>

test.cfm

<cfset propertyValue = application.getProperty("siteName") />
<cfdump var="#propertyValue#" />
Greg S
Thanks Greg. Essentially it is one code base that will run multiple web sites and change depending on the URL. So a particular site will have information specific to itself (site name, for example).
Tom Hubbard
Thanks for the extra info Tom. I've updated the answer above. Not sure the best way to manage multiple sites off a single code-base but hope this helps you along your way.
Greg S
Thanks Greg. This is great, it answers the question as well as giving a better way to do it.
Tom Hubbard
Very nice example! +1
Jas Panesar
A: 

you might also want to use the technique discussed here

rip747