RE: Help with CFC and recursion?
Thanks for the tips Sean, Raymond, et al I had tried using the VAR bit before, but the code choked. I didn't even think of doing it in CFSET tags. (And, I learned that a CFTRY tag is interpreted as executable code.) The function is working now. As for my use of the CFPROPERTY tags, I know they are kinda useless in the manner I'm using them, EXCEPT for documentation. If you pull up the CFC in a browser directly (i.e. http://myserver/mydir/mycfc.cfc), then you get a very nicely formated page documenting everything there is to know about the component. If you don't use the CFPROPERTY tag, then the properties section is empty. We are intending to print these screens to document our classes, so having the properties listed is an added bonus. Also, some of our components will likely become web services in the near future - we're still getting the core code into place so we can proceed with the presentation layer. Thanks for the input on recursion, and some tips on CFProperty - on which I have not been able to find any great details. Shawn -Original Message- From: Sean A Corfield [mailto:[EMAIL PROTECTED] Sent: Monday, May 26, 2003 8:07 PM To: CF-Talk Subject: Re: Help with CFC and recursion? On Monday, May 26, 2003, at 17:41 US/Pacific, Shawn Grover wrote: I've tried a number of combinations for the code, and always seem to get a similar result. You need to use 'var' to declare your variables local - otherwise they are just instance variables and get overwritten by each recursive call. cfcomponent cfproperty name=Category type=caa.intranet.cfc.data.category Why bother with this if it isn't a Web Service? cfproperty has no useful purpose except for type-checking Web Service returns. cfscript this.Category = createObject(component, caa.intranet.cfc.data.category); this.Category.Clear(); this.List = this.Category.List(); /cfscript cffunction name=BuildTree access=public returntype=string cfset qRoot = getChildren(0) cfset var qRoot = getChildren(0) cfset sTree = cfset var sTree = cfloop query=qRoot cfset sTree = sTree AddNode(qRoot.Category_ID, qRoot.Category_Name) /cfloop cfreturn sTree /cffunction cffunction name=AddNode access=private returntype=string output=no cfargument name=CategoryID type=numeric required=Yes cfargument name=CategoryName type=string required=Yes cfset var sChild = cfset var qChildren = cfscript sChild = [#JSStringFormat(Arguments.CategoryName)#, 'javascript:node_clicked(#Arguments.CategoryID#);', null; qChildren = getChildren(Arguments.CategoryID); for (x=1; x lte qChildren.RecordCount; x=x+1) { sChild = sChild AddNode(qChildren.Category_ID[x], qChildren.Category_Name[x]); } sChild = sChild ], ; /cfscript cfreturn sChild /cffunction cffunction name=getChildren access=public returntype=query cfargument name=ParentID type=numeric required=Yes cfset var qTemp = this.List cfset var qChildList = 0 cfdump var=#Arguments# cfset qTemp = this.List You can delete this line ^^^ cfquery name=qChildList dbtype=query Select * From qTemp Where Parent_ID = #Arguments.ParentID#; /cfquery cfreturn qChildList /cffunction /cfcomponent ~| Archives: http://www.houseoffusion.com/cf_lists/index.cfm?forumid=4 Subscription: http://www.houseoffusion.com/cf_lists/index.cfm?method=subscribeforumid=4 FAQ: http://www.thenetprofits.co.uk/coldfusion/faq Signup for the Fusion Authority news alert and keep up with the latest news in ColdFusion and related topics. http://www.fusionauthority.com/signup.cfm Unsubscribe: http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=89.70.4
Re: Help with CFC and recursion?
On Tuesday, May 27, 2003, at 13:14 US/Pacific, Shawn Grover wrote: As for my use of the CFPROPERTY tags, I know they are kinda useless in the manner I'm using them, EXCEPT for documentation. And of course it all depends on whether you want to use public data members - this scope - which you might want to document with cfproperty or non-public data members - unnamed scope - which you would not want to document with cfproperty (since the documentation is of the public interface). Are other folks relying on cfproperty for auto-documenting public data members? How do you deal with keeping the cfproperty tags in sync with what you actually do with this scope variables? Sean A Corfield -- http://www.corfield.org/blog/ If you're not annoying somebody, you're not really alive. -- Margaret Atwood ~| Archives: http://www.houseoffusion.com/cf_lists/index.cfm?forumid=4 Subscription: http://www.houseoffusion.com/cf_lists/index.cfm?method=subscribeforumid=4 FAQ: http://www.thenetprofits.co.uk/coldfusion/faq This list and all House of Fusion resources hosted by CFHosting.com. The place for dependable ColdFusion Hosting. http://www.cfhosting.com Unsubscribe: http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=89.70.4
RE: Help with CFC and recursion?
We're declaring a Clear function which initializes the THIS properties to a valid, known state. Our procedure is to ensure the clear function matches the CFPROPERTY declarations, and we call the Clear function when the CFC is initialized. -Original Message- From: Sean A Corfield [mailto:[EMAIL PROTECTED] Sent: Tuesday, May 27, 2003 4:10 PM To: CF-Talk Subject: Re: Help with CFC and recursion? snip/ Are other folks relying on cfproperty for auto-documenting public data members? How do you deal with keeping the cfproperty tags in sync with what you actually do with this scope variables? Sean A Corfield -- http://www.corfield.org/blog/ If you're not annoying somebody, you're not really alive. -- Margaret Atwood ~| Archives: http://www.houseoffusion.com/cf_lists/index.cfm?forumid=4 Subscription: http://www.houseoffusion.com/cf_lists/index.cfm?method=subscribeforumid=4 FAQ: http://www.thenetprofits.co.uk/coldfusion/faq Get the mailserver that powers this list at http://www.coolfusion.com Unsubscribe: http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=89.70.4
Re: Help with CFC and recursion?
On Tuesday, May 27, 2003, at 16:20 US/Pacific, Shawn Grover wrote: We're declaring a Clear function which initializes the THIS properties to a valid, known state. Our procedure is to ensure the clear function matches the CFPROPERTY declarations, and we call the Clear function when the CFC is initialized. And what's to stop some arbitrary method just setting this.foo to some value? (or, worse, some client code that instantiates a CFC and then sets the public data) foo.cfc: cfcomponent cfproperty name=bar type=numeric/ cffunction name=clear cfset this.bar = 0/ /cffunction ... /cfcomponent bogus.cfm: cfset foo = createObject(component,foo)/ cfset foo.clear()/ cfset foo.bar = Hah! I'm a STRING now!/ Sean A Corfield -- http://www.corfield.org/blog/ If you're not annoying somebody, you're not really alive. -- Margaret Atwood ~| Archives: http://www.houseoffusion.com/cf_lists/index.cfm?forumid=4 Subscription: http://www.houseoffusion.com/cf_lists/index.cfm?method=subscribeforumid=4 FAQ: http://www.thenetprofits.co.uk/coldfusion/faq Host with the leader in ColdFusion hosting. Voted #1 ColdFusion host by CF Developers. Offering shared and dedicated hosting options. www.cfxhosting.com/default.cfm?redirect=10481 Unsubscribe: http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=89.70.4
RE: Help with CFC and recursion?
This falls under the black box concept, in that the component isn't supposed to know about the environement is getting used in. We don't care if some arbitrary code changes the properties. However, we do care about having valid data before it is placed into the database. So, our components (data access components at least) have an isValid() function which is public, and is also called internally when a save is done. When I first started exploring components in detail (all of 3 weeks ago), this was the first issue we ran into - you can't really type cast your properties, then enforce that type casting (at least not when using a CFC as a component - I understand this may be different when used as a web service). We were initially going to create get and set methods for member variables (not in the THIS scope), but quickly realized this was meaningless, because I was free to set variables on the object willy-nilly. For example, a component might have two official properties - say x and y. I can freely create my own properties by assigning a value to them (like javascript)... : cfscript oPos = createObject(component, myposition); oPos.x = 5; oPos.y = 6; oPos.z = 15;//This is not an officially supported property oPos.MyOwnProperty = Hi ya Bob; //another unofficial property /cfscript If you do a cfdump of the oPos object, it DOES reflect the two additional properties, even though they were not defined in the CFC. So, doing get's and set's to enforce data type becomes meaningless - instead of saying oObj.getProperty(); a user could do oObj.Property = 1;, and x = oObj.Property;, bypassing the functions. We decided it was easiest to simply validate the properties before saves, and allow the calling code to call the isValid method as well. k, I've rambled on long enough... hope this helps someone out there. Shawn -Original Message- From: Sean A Corfield [mailto:[EMAIL PROTECTED] Sent: Tuesday, May 27, 2003 5:30 PM To: CF-Talk Subject: Re: Help with CFC and recursion? On Tuesday, May 27, 2003, at 16:20 US/Pacific, Shawn Grover wrote: We're declaring a Clear function which initializes the THIS properties to a valid, known state. Our procedure is to ensure the clear function matches the CFPROPERTY declarations, and we call the Clear function when the CFC is initialized. And what's to stop some arbitrary method just setting this.foo to some value? (or, worse, some client code that instantiates a CFC and then sets the public data) foo.cfc: cfcomponent cfproperty name=bar type=numeric/ cffunction name=clear cfset this.bar = 0/ /cffunction ... /cfcomponent bogus.cfm: cfset foo = createObject(component,foo)/ cfset foo.clear()/ cfset foo.bar = Hah! I'm a STRING now!/ Sean A Corfield -- http://www.corfield.org/blog/ If you're not annoying somebody, you're not really alive. -- Margaret Atwood ~| Archives: http://www.houseoffusion.com/cf_lists/index.cfm?forumid=4 Subscription: http://www.houseoffusion.com/cf_lists/index.cfm?method=subscribeforumid=4 FAQ: http://www.thenetprofits.co.uk/coldfusion/faq Get the mailserver that powers this list at http://www.coolfusion.com Unsubscribe: http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=89.70.4
Re: Help with CFC and recursion?
On Tuesday, May 27, 2003, at 17:30 US/Pacific, Shawn Grover wrote: We were initially going to create get and set methods for member variables (not in the THIS scope), but quickly realized this was meaningless, because I was free to set variables on the object willy-nilly. But the variables you set on the object are in this scope which you can ignore inside the CFC and only use the unnamed scope. cfscript oPos = createObject(component, myposition); oPos.x = 5; oPos.y = 6; oPos.z = 15;//This is not an officially supported property oPos.MyOwnProperty = Hi ya Bob; //another unofficial property /cfscript If you do a cfdump of the oPos object, it DOES reflect the two additional properties, even though they were not defined in the CFC. Correct. But cfdump does not show any non-public data that the CFC has set itself, which is the key point. So, doing get's and set's to enforce data type becomes meaningless - instead of saying oObj.getProperty(); a user could do oObj.Property = 1;, and x = oObj.Property;, bypassing the functions. Consider this: foo.cfc: cfcomponent cffunction name=getFoo returntype=string cfreturn foo/ cffunction cffunction name=setFoo cfargument name=newFoo type=string/ cfset foo = arguments.newFoo/ /cffunction cfcomponent rogue.cfc: cfset foo = createObject(component,foo)/ cfset foo.setFoo(hello)/ cfoutput#foo.getFoo()#/cfoutput cfset foo.foo = goodbye/ cfoutput#foo.getFoo()#/cfoutput You will see that using the unnamed scope instead of this scope protects your data - the foo.foo = goodbye has no effect on 'foo' inside the CFC (because it sets 'this.foo' instead). A common idiom folks seem to have adopted is actually this: foo.cfc: cfcomponent cfset instance = structNew()/ cffunction name=getFoo returntype=string cfreturn instance.foo/ cffunction cffunction name=setFoo cfargument name=foo type=string/ cfset instance.foo = arguments.foo/ /cffunction cfcomponent This creates a non-public (and therefore protected) instance variable (called 'instance') which acts like a scope for all your instance data - and also allows your setXxx() method to use the same name for its argument as for the instance variable itself (which is not possible using the unnamed scope). In theory, you ought to be able to use variables scope instead of the instance 'scope' shown above but, right now, there's a bug in CFMX which makes variables scope break in CFCs (which will get fixed in due course). Hope that helps explain how to use get/set to encapsulate your data and avoid 'malicious' code outside the object from messing with it. Sean A Corfield -- http://www.corfield.org/blog/ If you're not annoying somebody, you're not really alive. -- Margaret Atwood ~| Archives: http://www.houseoffusion.com/cf_lists/index.cfm?forumid=4 Subscription: http://www.houseoffusion.com/cf_lists/index.cfm?method=subscribeforumid=4 FAQ: http://www.thenetprofits.co.uk/coldfusion/faq Get the mailserver that powers this list at http://www.coolfusion.com Unsubscribe: http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=89.70.4