Using Constants in ColdFusion Components

In code we often need to make use of constant values. It is good practice to use named constants rather than literal values, but what is a good technique for managing constants in an object oriented ColdFusion application? One technique is to break your constants down into separate files that relate to their particular area. For example you might have a set of files:

/constants/global.cfm

/constants/products.cfm

/constants/users.cfm

Etc.

Inside each file you would define the constants for that area. For example, for the products.cfm file you may write:

<cfscript>
 
// Define the product constant namespace.
 
structGet("constant.product");
 
// Product status constants.
 
constant.product.STATUS_ACTIVE = 1;
constant.product.STATUS_INACTIVE = 2;
constant.product.STATUS_ARCHIVED = 3;
 
// Other product related constants here, etc.
 
constant.product.IS_FEATURE = 1;
constant.product.IS_SPECIAL = 2;
 
</cfscript>

Here you can use the structGet() function to create a “namespace” for your constants. This means that if you have identical constant names in different areas then they will not overlap.

Then, wherever you need to use the constants you can include these directly into your components:

<cfcomponent output="false">
 
	<cfinclude template="/constants/global.cfm">
	<cfinclude template="/constants/products.cfm">
 
	<!--- Functions here... --->
 
</cfcomponent>

This would cause the constants to all be loaded into the component’s variables scope. You could them use them in a function as follows:

<cffunction name="isActive" output="false">
	<cfreturn getStatusId() eq constant.product.STATUS_ACTIVE>
</cffunction>

This does not appear to be a particularly object oriented technique but seems a little nicer that some of the alternatives, such as referencing an external scope (eg constants stored in the application scope) or passing/injecting a “Constants” object into other objects that require it.

What do you think? How do you handle constants in ColdFusion components?

This entry was posted in OOP and tagged , , . Bookmark the permalink. Both comments and trackbacks are currently closed.

9 Comments

  1. Posted May 9, 2008 at 8:23 am | Permalink

    "How do you handle constants in ColdFusion components"
    I have ColdSpring inject them, normaly from a Map in the ColdSpring XML though if their more complicated or user-dependant I’ll do a fill blown ‘EnvironmentService’ that can be injected into all the components.

  2. Posted May 9, 2008 at 12:04 pm | Permalink

    Like Tom I use ColdSpring for this. I have a MapFactoryBean that is declared with all of the constants I need and then I have that injected into my CFCs. It’s very clean and simple.

  3. Posted May 9, 2008 at 1:36 pm | Permalink

    Thanks Tom, Sean

    I originally started off with a ColdSpring bean of constants, but when working on a ColdSpring / Transfer application I could not see a simple way to get my constants into Transfer Decorators, so I switched to cfm’s.

    However, just now found Brian Kotek’s Transfer bean injector:
    http://www.briankotek.com/blog/index.cfm/2008/1/14/My-Transfer-Decorator-Bean-Injector-Observer-Is-Now-Available

    Thanks Brian!

  4. Posted May 9, 2008 at 4:59 pm | Permalink

    For reference, the MapFactoryBean is a component available in the CVS version of ColdSpring. Using this component you can create a bean such as:

    <bean id="appConstants" class="coldspring.beans.factory.config.MapFactoryBean">
    <property name="sourceMap">
    <map>
    <entry key="product">
    <map>
    <entry key="STATUS_ACTIVE"><value>1</value></entry>
    <entry key="STATUS_INACTIVE"><value>2</value></entry>
    <entry key="STATUS_ARCHIVED"><value>3</value></entry>
    <entry key="user">
    <map>
    <entry key="STATUS_ARCHIVED"><value>1</value></entry>
    <entry key="ADMIN_USER_ID"><value>1</value></entry>
    </map>
    </entry>
    </map>
    </entry>
    <entry key="user">
    <map>
    <entry key="STATUS_ARCHIVED"><value>1</value></entry>
    <entry key="ADMIN_USER_ID"><value>1</value></entry>
    </map>
    </entry>
    </map>
    </property>
    </bean>

    Then using code such as:

    <cfset constants = factory.getBean("appConstants")>

    You get a nested set of structures that may be used as constants.

    I also noticed that you cannot use a bean with id="constants". This causes a bean creation exception.

  5. Posted March 15, 2009 at 11:41 am | Permalink

    I think for bigger frameworks the bean instatiation is a good id; for smaller projects we often use our own application and session management, which is instatiating the variables by special cfm-files.

    The frameworks often have the problem of performance; a small request will mostly take 500 – 700ms, which is caused by many, many cfc for framework-startup…

    the glory way is not always the same… everyone has to check, which kind of app is used in which way…. a cms often has other requirements than a gui of a management interface, used inside a company…

  6. Posted March 15, 2009 at 3:09 pm | Permalink

    Hi Christian

    Yes, certainly something like ColdSpring may not be for everybody.

    However I now quite like the idea of storing constants in a single component that lives in the application scope. As it is only a single component created at application startup, it should have no practical impact on performance.

    So in a non-framework or simplified application, you could have:

    On application start, create some service that provides access to constants. When this object is created, the constants would be created at the same time.

    <cfset application.appService = createObject("component","com.AppService").init()>

    And within the application code, you would make a call such as:

    <cfset constants = application.appService.getConstants()>

    that would return a struct containing the application constants.

  7. Sean
    Posted January 26, 2010 at 6:32 pm | Permalink

    How about putting all global things in a file that is cfincluded by application.cfc, then in onApplicationStart collect (structure) pointers (to variables or functions) in global (application scope), then in any cfc that requires constants or global functions, refer to the global structure:

    See my comments at:
    [URL="http://www.bennadel.com/blog/1776-Creating-Globally-Accessible-User-Defined-Functions-In-ColdFusion-Safer-Version-.htm?&_=0.905060270905669#comments_24513"]Creating Globally Accessible User Defined Functions In ColdFusion (Safer Version)[/URL]

    Here was the final solution:

    [Put in application.cfc:]

    [CODE]

    <cffunction name="onApplicationStart">

    . . . snip . . .

    <cfscript>
    application.globalmethods = structnew();
    keys = structkeylist(this);
    for (i=1; i LTE listlen(keys); i=i+1) {
    key = listgetat(keys,i);
    if (iscustomfunction(this[key]) and left(lcase(key),2) NEQ "on")
    structinsert(application.globalmethods, key, this[key]);
    }
    application.registerglobalmethods = this.registerglobalmethods;
    </cfscript>

    . . . snip . . .

    </cffunction>

    <cfinclude template="GlobalFunctions.cfm">

    <cffunction name="registerglobalmethods" output="no">
    <cfset StructAppend(variables, application.globalmethods, true)>
    </cffunction>

    [/CODE]

    Finally, in any cfc that uses a global function, call the register function, then you can use any global function (with no scope prefix):

    [CODE]<cfset application.registerglobalmethods();>[/CODE]

    Now, you could skip the register function and just use:

    [CODE]<cfset StructAppend(variables, application.globalmethods, true)>[/CODE]

    when ever a cfc needed to use global functions. But I think this is more readable.

  8. Posted January 30, 2010 at 1:54 am | Permalink

    Whilst I neither condone nor condemn the suggested solution, I wanted to point out that you can short circuit that code quite a bit by using:

    for ( key in this ) …

  9. Sean
    Posted January 30, 2010 at 2:22 pm | Permalink

    Thanks Sean.