Samer asks:
I know CFCs should never access SESSION/CGI variables, and these variables should be passed as arguments. In my case i have a lot of CFCs that calls another CFC "for logging" which reads SESSION and CGI variables, is there a way not to pass these variables as arguments in all CFCs?
I think you touch on multiple things here - and each thing you touch on will have multiple answers with a lot of it being "it depends." So get ready Samer for an overload from me and my readers. Let me begin by breaking this up into what I see as the main concerns.
- CFCs and accessing Session/CGI variables
- Multiple CFCs using some common other CFC
Let's start with issue one. First off - I know I've done it myself, but I try to refrain from saying never. The issue isn't with Session variables in a CFC, but with outside variables in general. You should try to make your CFCs as encapsulated as possible. I assume most folks 'get' that concept so I won't cover it a lot - but I bring it up to remind folks that it isn't just Session variables you wouldn't want to use (normally), but anything that hinders encapsulation.
That being said, from time to time I've used Session variables in my Controller CFCs in Model-Glue applications. I kept my model layer as pure as possible, but found a need to directly reference session items in the controller layer. I did try to make it as 'nice' as possible. So for example, any time I needed a user object stored in the session scope, I'd call a getCurrentUser() method. That method directly accessed the session scope. That way in case things changed I'd only have one thing to change.
I'd also argue that a logging CFC is a good example of something that can break encapsulation. I certainly wouldn't bother passing in CGI info when setting up a logger CFC as the CGI scope is always there.
Point 2 - this is exactly where something like ColdSpring comes into play. Whenever you get an application that has multiple CFCs and CFCs that depend on each other, you want to look into a framework to make the dependencies easier to handle. Do not do like I did and delay picking it up. As I've said before, I wish I had picked up ColdSpring a lot earlier as it would have made my life a lot easier.
Archived Comments
I have adopted others approach that, much like Ray mentioned he does to have a function so he can change it in only 1 place, I do in a more generic method by having a facade component with generic get/set type methods, that is loaded up and told what scope it works with initially. So, I load up a singleton called anything you want, say userState. Then all throughout your application you do userState.get("username"), userState.exists(), userState.set("username","chris"). Then if you ever had to swap from session to client, you just change your initialization of your facade component, and none of your application has to be modified. =)
Good point Ray ... I always create some sort of Scope Facade, which is a CFC with a sole purpose of communicating with a scope, 'session' for example. Then I end up with a single point of communication and other CFCs that require it can use my sessionFacade. That allows to abstract session from all CFCs, which means I could even change how I handle sessions and throw it into a shared database layer if I wanted, or as a simple example, change the storage location inside the session scope... Furthermore, I never store directly under session, or application. I create a structure to hold my data because I dont want any CFC with access to the application facade to be able to access by application functions, name, timeout, etc...
HTH
I wrote up how we're using a Session Facade here:
http://www.iknowkungfoo.com...
We now have a base SessionFacade.cfc and each application has their own that extends the base. We pass the SessionFacade into other objects as needed so that no other object is directly accessing the session scope.
This gives us focal points for managing session variables across applications and it makes sure that everything is locked correctly for reads and writes.
Our old site read from and wrote to the session scope anywhere it pleased. People would log in and get someone else's session info so often, we just told them to log in again and see if that helped.
We use a session facade very similar to what Rob posted above. It works fantastic in the CFCs and eliminates the session dependency.
Another common practice we have which isn't as nice but gets the job done, is pass the variable as an argument to functions but give it a default value of value="#session.whatever#" so it only needs to be passed in by functions that don't have access to the session scope.
I tend to agree with Ray, however that dependency injection is really the way to go here with a session facade.
The "Session facade" thing is definitely the way to go. I have a couple of nitpicking gripes about the name, though.
1. Session Facade is also a J2EE pattern that provides a stateful facade in front of a set of stateless beans. IOW, the client interacts directly with the session facade, which then talks to the back end system. This sounds like a facade to me. The "Session facade" that CFers talk about is just plain old encapsulation. Yep, I told you it was nitpicking!
2. Name the object for what it represents, not how it's implemented. I don't call my Invoice object InvoiceDatabaseRecordFacade, I just call it Invoice. This thing is an abstraction that represents a user's session, so what's wrong with UserSession.cfc? Or even just Session.cfc.
Ok, gripe over. Apologies for the inconvienece, we now return you to the scheduled programming...
ray, question for you. i know it's a good idea to use the duplicate() function when pulling a variable out of the session, but what about when setting a variable IN to the session?
found some info on it from adobe (http://www.adobe.com/devnet... that i understood as not to worry if the original variable was not of shared scope...but i am looking for a 2nd opinion.
thanks in advance.
thanks.
"i know it's a good idea to use the duplicate() function when pulling a variable out of the session"
Actually, no, it isn't. In the "old days" (pre-CFMX) it was, but not anymore.
As for setting a variable, you wouldn't use duplicate either, unless you explicitly needed to. (And you probably don't.)
As to that article - it is probably close to 10 years old. Unfortunately, there is no date stamp on it.
thanks for the feedback ray.
tricky adobe...going for 'timeless' i guess!