Ok, three things I'd like to talk about:

1. Great post. These are exactly the kinds of questions I'd like to see more CF developers ask.

2. regarding your user object in session:

<cfset Session.user = CreateObject( "component", "UserCFC" ).init(
dsn=Application.DSN, scope="Session" ) >
do I need to lock the session scope when calling a method of
Session.user?

I'd recommend looking into the Facade design pattern to address this problem. I made a post outlining how we're using it to work with objects in session:

http://www.iknowkungfoo.com/blog/index.cfm/2007/2/11/Using-a-Session-Facade-to-handle-evolving-session-variables

I think you're using your UserCFC as a Facade since you seem to be using it to manage session variables related to the user. We use a SessionFacade.cfc and a UserFacade.cfc

In Application.cfc:onRequestStart(), we use a lock to set the sessionFacade into the request scope for the life of the page request.

<cflock ...>
        <cfset request.SessionFacade = application.SessionFacade />
</cflock>

Now we can safely output #request.SessionFacade.getUser.get*()# anywhere on the page. The session.user object is read using a lock inside SessionFacade.getUser().

If you need to access session scoped variables inside another component, then you can inject the SessionFacade into that component as Nando described.

3. What Nando mentioned about making a reference to an object:

"In reality, all that is passed is a reference to the object. CFAS creates a variable when you instantiate an object in memory, and when you give it some name in some scope, then it has a reference to that variable. CFCs are passed by reference"

Kelly Brown has a great post about that:
http://www.kellyjo.com/blog/index.cfm/2007/1/4/There-are-no-Pointers-in-ColdFusion

To get around this problem with simple variable types (i.e. string, struct, numeric), you can use duplicate() to create a separate copy of an existing variable:

<cfset variables.foo = duplicate(session.foo) />

Now you can change the value of variables.foo without affecting the value of session.foo. We can't use duplicate() on objects (CFCs) yet and I've no idea when we ever will. This is why you have to be very careful when you're injecting session objects into other objects.

I found a problem with exactly that today (the day before open beta of our new site. Joy!).

Another developer had injected a core session object into another object in order to pass in its arguments in one shot. The code looked something like this:

Application.cfc:onRequestStart()

        <cflock ...>
                <!--- session.data is a bean --->
                <cfset request.data = session.data />
        </cflock>

some.cfm

        <cfset data = request.data />
        <--- ... --->
        <cfset moreData = createObject("component", "moreData").init()/>
<cfset moreDataDAO = createObject("component", "moreDataObj").init( DSN = request.DSN ) />
        <cfset moreData.read( moreData = moreData, data = data )/>

moreDataDAO.cfc:read()

        <cfset arguments.data.init( ... ) />
        <!--- etc. --->

moreData extends data and the intent was to inject moreData with data and call data.get*() inside moreData.init(). The problem is that he called data.init() instead of just passing the data bean into moreData.init().

So let's follow the chain of references to see what happened:

session.data -> request.data -> variables.data -> arguments.data.init()

data.init() was called from inside the DAO without passing in values for all the arguments of the init method. Whenever this process was run, the data bean stayed in session, but its contents were reverted to their default, empty values.

Fortunately it only took a few minutes to put a band-aid in place. A complete fix should be ready by the end of the week. I think this is an excellent example of how fragile applications can become when we forget (or don't know) that CFCs can only be referenced in CF.

It's late and this reply has gone on long enough for now. I'm going to clean up this last section and post it to my site along with some additional comments. I hope everyone's replies have helped.

-- Adrian J. Moreno
-- Senior Web Developer, Technical Lead
-- Unitrin Specialty
-- Blog @ http://iKnowKungFoo.com


You are subscribed to cfcdev. To unsubscribe, please follow the instructions at 
http://www.cfczone.org/listserv.cfm

CFCDev is supported by:
Katapult Media, Inc.
We are cool code geeks looking for fun projects to rock!
www.katapultmedia.com

An archive of the CFCDev list is available at 
www.mail-archive.com/cfcdev@cfczone.org

Reply via email to