As others have mentioned... don't fight OO. :)  It takes a bit of time
to adjust but it will all come together and you'll be a more productive
developer as a result.

As someone mentioned, the variable scope is local to the page (doesn't
matter if the file ends in cfc or cfm).  You aren't *including* a
component, you're creating a copy of it in memory.  When you initialize
each of the objects, sometimes they require variables to function (DSN
is a good example).  Take this as an example...

Let's say you want to group all of your data access (queries) functions
into one CFC.  All of these functions merely get/insert/update based
upon arguments sent to them.  While they may return different results,
they are essentially 'reset' after they are executed.  Since you're
going to have several methods that all depend on the same DSN, you can
inject the DSN into the init() function and store the variable in a
scope that is available to all methods on that 'page'.   Since this CFC
merely returns queries, you could store this CFC in a scope that allows
it to persist across many page requests.  For the purpose of learning,
think about it this way...


>From Application.cfc...

<cffunction name="onApplicationStart()" returntype="boolean"
output="false">

   <!--- Store DB info to be injected into objects that need it --->
   <cfset var dsn = "myDsn" />
   <cfset var dbUser = "myUser" />
   <cfset var dbPwd = "myPwd" />

   <!--- Create all of my objects that perform CRUD operations --->
   <cfset oUserGateway =
createObject("component","path.to.UserGateway").init(myDsn,myUser,myPwd)
/>
   <cfset oHomeGateway =
createObject("component","path.to.UserGateway").init(myDsn,myUser,myPwd)
/>
   <cfset oNewsletterGateway =
createObject("component","path.to.NewsletterGateway").init(myDsn,myUser,
myPwd) />

   ... include any other application stuff you want ...

</cffunction>

When you're application loads, you create variables to hold your DB
credentials and DSN.  Then you inject variables into each of your CFCs
that communicate with that DB.  Now let's look inside one of those
Gateway objects.

>From UserGateway.cfc...

<!--- Pseudo constructor method --->
<cffunction name="init" access="public" output="no"
returntype="UserGateway">
   <cfargument name="DSN" type="string" required="yes" hint="ColdFusion
datasource name." />
   <cfargument name="dbUsr" type="string" required="yes"
hint="ColdFusion datasource's username." />
   <cfargument name="dbPwd" type="string" required="yes"
hint="ColdFusion datasource's password." />
      
     <cfset VARIABLES.dsn = ARGUMENTS.dsn />
     <cfset VARIABLES.dbUsr = ARGUMENTS.dbUsr />
     <cfset VARIABLEs.dbPwd = ARGUMENTS.dbPwd />
                
     <cfreturn this />
</cffunction>

<!--- Get list of users by is_Active database field --->
<cffunction name="getUsers" access="public" output="no"
returntype="query">
   <cfargument name="isActive" type="boolean" required="no"
default="false" hint="Limit results to users marked active in
database."/>

   <!--- var all variables I want to disappear after this method runs
--->
   <cfset var qOut = "" />

   <!--- Get users --->
   <cfquery name="qOut" datasource="variables.dsn"
username="variables.dbUsr" password="variables.dbPwd">
      SELECT *
      FROM tbl_User
      WHERE 0=0 <cfif Arguments.isActive> AND is_Active = 1</cfif>
   </cfquery>

   <cfreturn qOut />
</cffunction>

There are a couple of OO practices going on here.  In Application.cfc,
you have injected the DB config/credentials into the init() method.  The
init() method simply passes those arguments into the variables scope
when the object is created. All of the methods from within that
component have access to the variables scope.  Therefore... all of them
have access to the DB config/credentials. So now you've got a
Application.oUserGateway object hanging around in memory for you to use
to perform CRUD operations on Users.  When it's time for you to get a
list of users, you can simply invoke the method on any template in the
application by doing this...

>From within XYC.cfm....

<!--- Get active users from database --->
<cfset qActiveUsers = Application.oUserGateway.getUsers(true) />

The <cfinvoke> equivalent is this...
<cfinvoke component="Application.oUserGateway" method="getUsers"
returnvariable="qActiveUsers" isActive="true" /> 

You see how much extra typing is involved with <cfinvoke>, which is why
I prefer the cfset way to do it.  Anyway, that invocation is accessing
the UserGateway from memory, running getUsers with an argument value of
'true'.  That may seem like quite a bit of typing just to get a user
list huh?  The beauty is, you can reuse that UserGateway object on
another app because it knows *nothing* about *anything* that hasn't been
explicitly provided.  If your DB password changes, you make ONE change
(onApplicationStart) and reload the app.  That is a basic form of
encapsulation.  If application requires new user fields in the database,
or is_active changes from Boolean to another datatype, it's much easier
to search/replace/modify all of your queries in one place.

Setting up the OO model takes some time.  What works best for you might
not work best for us.  This topic seems pretty popular and it doesn't
seem to be too hard to get opinions on it.  Keep trying to work through
it brotha. :)  Keep in mind, this example is just for general CRUD
components.  You don't want to load every object into the Application
scope (especially on a shared server).   Try to stay away from using
CGI, session, request, application, or server scopes from within your
components.  Instead, pass those values into a method via an argument.


-----Original Message-----
From: Rick Faircloth [mailto:[EMAIL PROTECTED] 
Sent: Saturday, June 21, 2008 10:11 PM
To: CF-Talk
Subject: RE: Clarification Required Concerning CFC...

> That would make less sense. The Variables scope is the local scope for
any
> CF program. CFM and CFC files are both CF programs.

It just seems to make little sense to have two scopes named the same
thing
which have nothing to do with each other.  It would be like me creating
two variables with the same name, but having different values.  Now that
would
be confusing!

I could have variables.time in a cfc that is 4pm, but variables.time
outside
a cfc which has the value of 4am, right?

If so, a scope exclusive to cfc's would seem to make more sense.
cfcVariables.time vs variables.time... instantly recognizable.

That's just the way it seems as I get started with cfc's...

Rick


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
Adobe® ColdFusion® 8 software 8 is the most important and dramatic release to 
date
Get the Free Trial
http://ad.doubleclick.net/clk;203748912;27390454;j

Archive: 
http://www.houseoffusion.com/groups/CF-Talk/message.cfm/messageid:307963
Subscription: http://www.houseoffusion.com/groups/CF-Talk/subscribe.cfm
Unsubscribe: 
http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=11502.10531.4

Reply via email to