Storing cfc functions in Application scope (caching?)

So, this might be a ‘duh’ question, but just read something about storing commonly used functions in the Application scope. And this would remove the need to create a new instance of said cfc on the calling page.

Anyone know of a decent tutorial explaining this? Tried looking this up on google, but came up with caching, and I don’t know that, that’s the right term for what I’m wanting.

I THINK I’m wanting to just load some common functions into a general scope which would allow easy access to them on pages, instead of having to use createObject or invoke each time.

Thanks.

I THINK I’m wanting to just load some common functions into a general scope which would allow easy access to them on pages

You can do something like this if you want a single methods available in every page request…


	<cffunction name="onRequest" access="public" returnType="void" output=true hint="Fires on the page request being processed">
        <cfargument name="targetPage2" type="string" required="true" hint="Passes in a copy of the currently requested page" />

<cfset variables.dump 	= createObject('component','com.udf.commonTags').dump />
			<cfset variables.abort 	= createObject('component','com.udf.commonTags').abort />
		
        <!--- Include the requested page. --->
        <cfinclude template="#arguments.targetPage2#" />
    </cffunction>

… that would go in your Application.cfc

That inserts two methods into every page call dump and abort.

I use them so I’ve got dump and abort functions available for cfscript
( ColdFusion doesn’t support in version 8 or below so it’s a bit of a hack! )

So I can now call them like so…


<cfscript>
[INDENT][/INDENT]dump("Hello World!"); 
[INDENT][/INDENT]abort();
</cfscript>

Cheers,
James

so with that being said…*shouldn’t the following work? Cause it’s not.

(inside onRequestStart, would prefer that it go into onSessionStart, none of the functions are data sensitive)


<cfset variables.helper = createObject("cfc.helper")>

and then refer to it like so (on page)


#helper.timeline_event(project_tasks,project.start_date,timeline_width)#

this only works if I create the “helper” object on the page itself.

Insert the function into Application.cfc and then place the function in the Request scope and access it there:

Here is the function added to application.cfc:

<cffunction name=“formatLongNumber” returntype=“string”>
<cfargument name=“intNumber” type=“numeric” required=“yes”>
<cfargument name=“blnShowDecimalNumber” type=“boolean” required=“no” default=“0”>

    &lt;cfset strVal = DecimalFormat(arguments.intNumber)&gt;
    
    &lt;cfif arguments.blnShowDecimalNumber EQ 0&gt;
    	&lt;cfset intLen = Len(strVal)-3&gt;
    	&lt;cfset strVal = #Left(strVal,intLen)#&gt;

    &lt;/cfif&gt;
    
    &lt;cfreturn strVal&gt;
    
&lt;/cffunction&gt;

The add this line to onRequestStart:

<cfset Request.formatLongNumber=This.formatLongNumber>

Use the function in any page:

#request.formatLongNumber(rsStatsSummary.intTotalMinutesAerobic)#

@downtroden

so with that being said…*shouldn’t the following work? Cause it’s not.

(inside onRequestStart, would prefer that it go into onSessionStart, none of the functions are data sensitive)

onRequestStart() does just that, the function is run at the start of every request and any variables assigned to it are dropped. If you want the functions to be available DURING the request on the variable scope then you’d need to use onRequest().

By all means though if when you say “general” scopes then Lemonizer’s last suggestion is fair enough, just remember you’ll need to call the function via request.xxxx before you can use it


@Lemonizer

Insert the function into Application.cfc and then place the function in the Request scope and access it there:

That’s not very usable though. What if I want to reuse that function in another project? It would be better to have that function in a CFC and then call it in onRequestStart() whenever its needed.

Putting it in a cfc is always a good idea so I can’t ague with that.

I’ve placed these types of utility functions in the Application.cfc because I always use the same Application.cfc file as a template from project to project.

<cfset structInsert( application, “com”, structNew(), true ) />
<cfset structInsert( application.com, “udf”, createObject( “component”, “path.to.cfc.nameOfCFC” ), true ) />

If you had a function in the udf.cfc called getInfo, you could call it from any page in the application via:

#application.com.udf.getInfo( param1, param2, param3… )#

or

<cfinvoke
component=“#application.com.udf#”
method=“getInfo”
param1=“a”
param2=“b”
param3=“”
/>

Doh!

I was focused on the “commonly used functions” in the original post.

Reading Aaron’s post woke me up.

Another approach you could take as well that mirrors Aaron’s post and addresses James’ point as well is to load the cfc into the application scope in the onApplicationStart function.

<cfset application.Functions = createObject(“component”,“cfc.Functions”).init(application.gDSN,application.gEncryptionKey)>

In this case I’m loading a cfc named functions that has misc functions in it. I’m passing in a datasource variable and encryption string variable that some of the functions will require - these are optional.

In the cfc, I’ve added an init function:

&lt;cffunction name="init" access="public" returnType="functions" output="false"&gt;
	&lt;cfargument name="dsn" type="string" required="true"&gt;
    &lt;cfargument name="EncryptionKey" type="string" required="true"&gt;
    
	&lt;cfset variables.gDSN = arguments.dsn&gt;
    &lt;cfset variables.gEncryptionKey = arguments.EncryptionKey&gt;
	&lt;cfreturn this&gt;
&lt;/cffunction&gt;

The returntype has to match the name assigned to the object assigned to the application scope. The rest of the code just assigns the datasource and encryption key to the variables scope so they can be used locally as cfc’s should not access the application scope.

When calling the a function in a page, just do something like this:

<cfif application.functions.IsEmail(form.txtEmailAddress)>

do something

</cfif>

This way cfc’s are only loaded once and you can access all of the methods from any page.

You still need to create the object, of use cfinvoke from if calling a function from another cfc.

In case anyone is interested, here is what I use from my Application.cfc file. I’ve left a few things in there that I use in my apps.

<cfcomponent>

	<!---Change these for developement--->
    <cfsetting showDebugOutput="no" requesttimeout="60">
	
   	
	<cfscript>
       this.name = "Application Name";
       this.applicationTimeout = createTimeSpan(0,0,20,0);
       this.clientmanagement= "yes";
       this.loginstorage = "session" ;
       this.sessionmanagement = "yes";
       this.sessiontimeout = createTimeSpan(0,0,20,0);
       this.setClientCookies = "yes";
       this.setDomainCookies = "no";
       this.scriptProtect = "all";  
   </cfscript>
   
   <cffunction name="onApplicationStart" output="false"> 

       <cfscript>
	   
	   	 //add any variables you want to use globally in your application

         //app defaults          
		 application.gDSN = "datasourcename";
		 application.gInputDate = "mm/dd/yyyy";
		 application.gMedDate = "mmm dd, yyyy";
		 application.gLongDate = "mmmm dd, yyyy";
		 application.sessions = 0;
		 
		 //conversion values
		 application.intLBSToKG = 0.45359237;
		 application.intInchesToCM = 2.54;
		 application.intMilesToYards = 1760;
		 application.intYardsToMeters = 0.9144;
		 application.intKMToMiles = 0.621371192;
		 
 

      </cfscript>


       <!---Create and Initialize Components--->
       
       <!---Repeat for each cfc you wish to load in the application scope--->
       <cfset application.Functions = createObject("component","cfc.Functions").init(param1,param2,...)>
		
        
                
       <cfreturn True>
       
   </cffunction>
   
   
   <cffunction name="onApplicationEnd" output="false"> 
      <cfargument name="applicationScope" required="true"> 
   </cffunction> 
   
   
   <cffunction name="onSessionStart" output="false"> 
   
		<!---Intialize any session variables--->
        <cfscript>
         session.started = now();
         session.current_page = "";
         session.current_page_clean = "";
         session.blnMetric = 0;
        </cfscript>
      
      
      <cflock scope="application" timeout="5" type="Exclusive">
         <cfset application.sessions = application.sessions + 1>
      </cflock>
   </cffunction>
   
   <cffunction name="onSessionEnd" output="false"> 
       <cfargument name = "sessionScope" required=true/>
       <cfargument name = "applicationScope" required=true/>
       <cfset var sessionLength = TimeFormat(Now() - sessionScope.started, "H:mm:ss")>
       
       <cflock name="AppLock" timeout="5" type="Exclusive">
            <cfset arguments.applicationScope.sessions = arguments.applicationScope.sessions - 1>
       </cflock>
       
       <cflog file="#this.name#" type="Information" 
            text="Session #arguments.sessionScope.sessionid# ended. Length: #sessionLength# Active sessions: #arguments.applicationScope.sessions#">
   </cffunction>
   
  
   <cffunction name="onRequestStart"> 
       <cfargument name="requestname" required="true">
       
        <cfscript>
       		session.current_page = #cgi.path_info# &"?"& #cgi.query_string#;
		 	session.current_page_clean = #cgi.path_info#;
		</cfscript>

        <!--- Let's re-initialize the application if "restartme" is present in the URL. --->
        <cfif StructKeyExists(URL,"restartme")>
            <cfset OnApplicationStart()>
        </cfif>
        
        <!---Load local functions into the request Scope--->
        <cfset Request.formatLongNumber=This.formatLongNumber>

   	</cffunction>
   
  
	<cffunction name="onError" output="true">
       <cfargument name="exception" required=true/>
       <cfargument name="eventName" type="String" required=true/>
       <!--- Log all errors. --->
       
       
       <!--- Display an error message if there is a page context. --->
       <cfif (trim(arguments.eventName) IS NOT "onSessionEnd") AND (trim(arguments.eventName) IS NOT "onApplicationEnd")>
                
            <cfmail to="you@you.com" from="you@you.com" subject="Error Report" type="html">   
            <cfoutput>
                <h2>An unexpected error occurred.</h2>
                <p>Error Event: #arguments.eventName#</p>
                <p>Error details:</p>
            </cfoutput>    
            <cfdump var=#arguments.exception#>
            
            </cfmail>
           <cflocation url="/error.cfm">
               
		</cfif>
    </cffunction>



    
<!---****************************************************************************************************************--->    
<!---Custom Functions--->
<!---****************************************************************************************************************--->    


	<cffunction name="formatLongNumber" returntype="string">
    	<cfargument name="intNumber" type="numeric" required="yes">
    	<cfargument name="blnShowDecimalNumber" type="boolean" required="no" default="0">
    
    	
        <cfset strVal = DecimalFormat(arguments.intNumber)>
        
        
        <cfif arguments.blnShowDecimalNumber EQ 0>
        	<cfset intLen = Len(strVal)-3>
        	<cfset strVal = #Left(strVal,intLen)#>

        </cfif>
        
        <cfreturn strVal>
	    
    </cffunction>
        
    


</cfcomponent>