On Tue, Dec 30, 2008 at 5:36 AM, Glyn Jackson wrote:

> application.appObjs = structNew();
> application.appObjs.securitySQLcfc =
> createObject("component","components.security");
> application.appObjs.commomSQLcfc =
> createObject("component","components.common-sql");



Just to make sure it's clear, that code above, by itself, does not cache
anything.  If you are using Application.cfc, then it would need to be placed
inside of onApplicationStart() in order to be cached.  If you are using
Application.cfm, then you would need to place it inside of a check to make
sure the variables do not exist.  For example:

<cfif NOT structKeyExists(application, "appObjs")>
     <!--- create the objects here --->
</cfif>



> A clients website gets around 5k of traffic a day and I have already cache
> some commonly used components however this was before Mr Sean Corfield
> reminder on CFCs, Scopes & Thread Safety! I have not had any reported issues
> with the site. I am being naive or lucky?



5k a day is very little traffic, in terms of large scale applications.
Having no issues/bugs with that amount of traffic is not, in my opinion, a
good judge of the application's safety.



> For example, most of the components are just simple SQL statement which I
> only want as a singleton, why create the object every time? I also don't
> think CFCs, Scopes & Thread Safety would be an issue here, is this correct
> or not? example code...



If the object is shared amongst the entire application, and only needed
once, then yes, create it once and cache it.  But it still has to be thread
safe.  ;-)



> <cffunction name="getProductMenu" returntype="query" hint="returns product
> menu">
> <cfquery name="productquery"  datasource="#application.appConfig.dbSource#"
> username="#application.appConfig.dbUsername#"
> password="#application.appConfig.dbPassword#">
>    SELECT s.storeId, s.name as storeName, s.metaDescription as storeMeta,
> s.pos, d.depId, d.name as depName, d.metaDescription as depMeta, d.pos,
> c.name as catName, c.metaDescription as catMeta, c.catId, (SELECT COUNT(*)
> as proCount FROM products p WHERE p.catId = c.catId AND p.active != 'off')
> as empt
>    FROM stores s
>    LEFT JOIN departments d on s.storeId = d.storeId
>    LEFT JOIN categories c on d.depId = c.depId
>    AND (SELECT COUNT(*) as proCount FROM products p WHERE p.catId = c.catId
> AND p.active != 'off') > 0
> </cfquery>
> <cfreturn productquery>
> </cffunction>



^ That is *not* thread safe.  While you'd probably get away with it since it
is not using any client-supplied variables, it still is not thread safe.
You need to var *all* variables that are not part of the object's
properties.

<cffunction name="getProductMenu">
     <cfset var productquery = "" />

     <cfquery name="productquery">
     <!-- the query --->
     </cfquery>

     <cfreturn productquery />
</cffunction>

^ Now we're thread safe.

Another point, not necessarily related to thread safety, but more of a best
practices thing.  You don't really want your objects directly referencing
things that are outside of them, such as your datasource information.  This
information should really be passed into the object when it is created.  For
example...

application.appObjs.securitySQLcfc =
createObject("component","components.security").init(dbSource:
application.appConfig.dbSource, dbUsername:
application.appConfig.dbUsername, dbPassword:
application.appConfig.dbPassword);

Note that we've added an init() method to the object creation, and are
passing in three arguments for our datasource information.  Now, inside of
the CFC we'll add an init() method.

<cffunction name="init" hint="I initialize the object" returntype="any"
output="false" access="public">
    <cfargument name="dbSource" type="string" required="true" />
    <cfargument name="dbUsername" type="string" required="true" />
    <cfargument name="dbPassword" type="string" required="true" />

    <cfscript>
         variables.dbSource = arguments.dbSource;
         variables.dbUsername = arguments.dbUsername;
         variables.dbPassword = arguments.dbPassword;

         return this;
     </cfscript>
</cffunction>

One note to make about the returntype of the init() method.  In the example
I used 'any', but in reality I would use the class type of the object.  So,
let's say that your CFC is named 'foo.cfc', I would use returntype="foo".

Now that we have passed in our datasource information, we can alter our
queries to use it rather than going outside of the object to get data.  This
is key to encapsulation.  So our productquery would now look like so:

<cfquery name="productquery" datasource="#variables.dbSource#"
username="#variables.dbUsername#" password="#variables.dbPassword#">
<!--- query here --->
</cfquery>

You can leave off the variables. if you'd like, but it would be better to
leave it there so that you know where those are coming from when looking
back at the code later.

Now then, I would also recommend studying about using getters and setters,
sometimes referred to as accessors and mutators.  But for the sake of
simplicity and not overwhelming you all at once, I shall refrain from going
into any detail.

I did not look in great detail at the cart code, but I did notice that it
too had queries that were not thread safe, as I've pointed out with the
productquery.  I also noticed that it directly references outside scopes,
which we've also already covered.  While you're definitely moving in the
right direction by starting to use CFCs, you'll want to do a lot more
studying on turning those CFCs into useful objects.

Hopefully some of the points I've made help, rather than muddying things
up.  The world of CFCs is a wonderful world, for sure, but it can definitely
be a bit overwhelming when one first heads down that road.  Stay the
course.  Study, study, study.  Try things out.  Break them.  Rebuild 'em
even better.  :-)


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

Archive: 
http://www.houseoffusion.com/groups/cf-talk/message.cfm/messageid:317270
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