1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Properly passing arguments from an invoke to a component

Discussion in 'Programming' started by ComboAlex, Aug 11, 2009.

  1. #1
    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):
     
    ComboAlex, Aug 11, 2009 IP
  2. Paul_K

    Paul_K Greenhorn

    Messages:
    85
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    18
    #2
    100% sure you saved the .cfc before running this it looks OK.
     
    Paul_K, Aug 18, 2009 IP
  3. cfStarlight

    cfStarlight Peon

    Messages:
    398
    Likes Received:
    3
    Best Answers:
    0
    Trophy Points:
    0
    #3
    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?
     
    cfStarlight, Aug 18, 2009 IP
  4. Paul_K

    Paul_K Greenhorn

    Messages:
    85
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    18
    #4
    Ha ha I totally missed that line I was lookign at the invoke.
     
    Paul_K, Aug 18, 2009 IP
  5. cfStarlight

    cfStarlight Peon

    Messages:
    398
    Likes Received:
    3
    Best Answers:
    0
    Trophy Points:
    0
    #5
    Yeah, I didn't notice it at first either ;-)
     
    cfStarlight, Aug 18, 2009 IP
  6. ComboAlex

    ComboAlex Peon

    Messages:
    14
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #6
    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.
     
    ComboAlex, Aug 19, 2009 IP
  7. Paul_K

    Paul_K Greenhorn

    Messages:
    85
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    18
    #7
    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 />
     
    Paul_K, Aug 19, 2009 IP
  8. ComboAlex

    ComboAlex Peon

    Messages:
    14
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #8
    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. ::D

    Do you want to say it is not possible to declare the local variables in CF8? I use FC8.
     
    ComboAlex, Aug 19, 2009 IP
  9. Paul_K

    Paul_K Greenhorn

    Messages:
    85
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    18
    #9
    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.
     
    Paul_K, Aug 19, 2009 IP
  10. ComboAlex

    ComboAlex Peon

    Messages:
    14
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #10
    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?
     
    ComboAlex, Aug 19, 2009 IP
  11. Paul_K

    Paul_K Greenhorn

    Messages:
    85
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    18
    #11
    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.
     
    Paul_K, Aug 19, 2009 IP
  12. ComboAlex

    ComboAlex Peon

    Messages:
    14
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #12
    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!
     
    ComboAlex, Aug 19, 2009 IP
  13. Paul_K

    Paul_K Greenhorn

    Messages:
    85
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    18
    #13
    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.
     
    Paul_K, Aug 19, 2009 IP
  14. cfStarlight

    cfStarlight Peon

    Messages:
    398
    Likes Received:
    3
    Best Answers:
    0
    Trophy Points:
    0
    #14
    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.
     
    cfStarlight, Aug 19, 2009 IP
  15. cfStarlight

    cfStarlight Peon

    Messages:
    398
    Likes Received:
    3
    Best Answers:
    0
    Trophy Points:
    0
    #15

    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.
     
    cfStarlight, Aug 19, 2009 IP
  16. ComboAlex

    ComboAlex Peon

    Messages:
    14
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #16
    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. :)
     
    ComboAlex, Aug 27, 2009 IP