OK, I am confused... error says: "The DATASOURCE parameter to the MakeBreadCrumb function is required but was not passed in. " But I am passing it! Don't I? Can anynone please help me solving this small problem? Thank you for helping me. Here's my invoke <body> <cfset databaseSource = "test"> <!--- defining the datasource (database name) ---> <cfset sourceTable = "testnavigation"> <!--- defining the table we will be getting the data from ---> <cfinvoke component="cfdocs.Recursive Navigation.cfcomponents.navigation" method="MakeBreadCrumb" returnvariable="MakeBreadCrumbRet"> <cfinvokeargument name="id" value="#URL.item#"/> <cfinvokeargument name="cnt" value="1"/> <cfinvokeargument name="dataSource" value="#databaseSource#"/> <cfinvokeargument name="table" value="#sourceTable#"/> </cfinvoke> </body> Code (markup): And here's my component: <component> <cffunction name="MakeBreadCrumb" access="public" returntype="array"> <cfargument name="id" type="numeric" required="yes" default=0 > <cfargument name="cnt" type="numeric" required="yes" default=0 > <cfargument name="dataSource" type="string" required="yes" > <cfargument name="table" type="string" required="yes"> <cfif arguments.cnt IS 0> <cfset breadCrumbArray=ArrayNew(1)> </cfif> <cfquery name="qryItem" datasource="#dataSource#"> SELECT parentid FROM #table# WHERE id = #arguments.id# </cfquery> <cfset breadCrumbArray[#arguments.cnt#]=arguments.id> <cfif qryItem.parentid IS NOT 0> <cfset MakeBreadCrumb(id = qryItem.parentid, cnt = arguments.cnt + 1) > <cfelse> <cfset reversedBreadCrumbArray = reverseArray(inputArray = breadCrumbArray)> </cfif> <cfreturn reversedBreadCrumbArray> </cffunction> </component> Code (markup):
No. You are not passing in all of the arguments when you call the function recursively. Also 1. Always use cfqueryparam. Especially with queries executed in a loop 2. VAR scope _all_ of your function variables 3. You realize "qryItem" poses a sql injection risk?
1. For now I don't know why this suggestion but will study more why to do that. 2. I am not sure that I understand what you mean by that. I know what scopes are... 3. Yeah, I know, I should probably use the strict MySQL syntax, am I right? I realized then that I was too tired so I totally missed the error that was throwing the real problem in my face, literally. Obviously the problem was where I recursively call the function. There are two arguments missing, I know now. Thanx to all again.
1. var scoping is very important example: <cffunction name="myMethod" returnType="void"> <cfset var temp /> <cfset var myCounter = 1 /> .....some code that uses temp and myCounter.... </cffunction> I prefer this method: <cffunction name="myMethod" returnType="void"> <cfset var local = {} /> <cfset local.myQueryResult /> <cfset local.myMathsRrsult /> .....some code that uses variables local to the method .... </cffunction> All variables are then protected from modification outside of the function and your not going to accidentally change variables that are not local to the function. The local scope exists implicitly in ColdFusion 9 so I recommend that way. 1 and 3 are related you should always be using <cfqueryparam />
Aha, I see. I had an idea you will head into the subject of local variables and I totally agree. In the first place I wanted to have local variables! I already had some problems because I wanted the variables within a function to be local. Since I am new to CF I was not exactly sure how to specify for to variables to be local. I know exactly what it means having local or global variables. You gave me a great help with the syntax. : Do you want to say it is not possible to declare the local variables in CF8? I use FC8.
In CF8 you can "make" the local scope by using <cfset var local = {} /> This is the same as <cfset var local = structNew() /> Then using local within your method.
I see, thought so. When using scopes it actually looks as if using structs (myStruct.myVariable). I already used structs in CF and I am used to them from C. I used to make linked-lists and each list node was a struct. In CF I used array of structs. Oh, and another thing... It looks like here in CF making a new struct is the same as making a new scope or a new object. Does that mean a scope is in fact nothing less than a object / struct? So, are structs, scopes and objects the same thing in CF?
Your right it is looking in a struct called local. But because I use var in the cfset its private to the method. This way anything I put into the local struct is private to the mothod aswell. So this in cf8 <cffunction name="myMethod" returnType="void"> <cfset var local = {} /> <cfset local.myQueryResult /> <cfset local.myMathsRrsult /> .....some code that uses variables local to the method .... </cffunction> Is exactly the same as this in cf9 <cffunction name="myMethod" returnType="void"> <cfset local.myQueryResult /> <cfset local.myMathsRrsult /> .....some code that uses variables local to the method .... </cffunction> Notice the <cfset var local = {} /> is removed in CF9. It will function with it aswell to be forward compatible the the ColdFusion compiler will ingore the line. In ColdFusion 9 local always exists as private within a method.
Ahaaa, I see. To sounds logical if you make a local struct (within a function) that everything that's under that struct is local too. Do you want to say that in CF9 you won't explicitly have to say for every variable that it is local? So does that mean that in CF9 any variable you create within a function is automatically local? If that's correct, that's great. Fom Java for example, I am used to have it this way. In Java I don't need to implicitly say that one variable in a function is local - it automatically is if defined in the function itself. For me it is a bit annoying to implicitly set local variables in CF8. Great help man! Thank you a lot!
Actually its a little different to that. In CF9 if you var scope a variable ie: <cfset var myVar = "Some text" /> Then later you can reference it as: <cfoutput>#myVar#</cfoutput> or <cfoutput>#local.myVar#</cfoutput> but if you don't var scope it it wont be in local. This is why I recommend prefixing method variables with local.
No. As Paul_K says you still have to use the "local" keyword explicitly. But at least you won't have to use the extra step of creating the "local" structure. It will already exist. Scopes and structures are very similar. In most cases you can use a "scope" the same as you would a "struct". But internally they're different classes and have a few behaviors that differ. So think of them as compatible in most senses, but not 100% the same.
The main reason to use cfqueryparam is for performance. When you use cfqueryparam, ColdFusion makes use of bind variables. So the db can cache and reuse the query plan improving the speed of queries. Especially, ones executed in a loop. The other reason is some minimal sql injection protection. It is a side effect/benefit of using bind variables. Technically you are using valid mySQL syntax ;-) The problem is you cannot protect table and columns from malicious sql strings, the way you can with simple values. At least not AFAIK. So if the values passed into the query are not scrubbed properly, it is a potential avenue of attack.
Uh... I almost lost track of all the posts I posted on different forums. So sorry guys for the delayed reply. Thank you guys, your advice was very helpful. Maybe soon I'll have more questions.