Trying to understand cfinvoke

I have a CF page that I use to update a database. At first I had all of my queries right on the page, but it got to be a bit of a mess, so I started storing the queries in cfc files and using <cfinvoke> to call them.

My problem is that I need to pass variables to the cfc via the cfinvoke tag, but I can’t for the life of me figure out how to do it.

I’m trying something like this:

<cfinvoke component="addpage" method="add" returnvariable="foo">
<cfinvokeargument name="foo" value="#somevar#">
</cfinvoke>

Then in the cfc:

<cfcomponent>
<cffunction name="add" access="public" returntype="string">
<cfargument name="foo" type="string" required="true">
<cfset bar = #arguments.foo#>
<cfquery name="addpage" datasource="hepoffice">
INSERT into table (col1)
VALUES (#bar#)
</cfquery>
</cffunction>
</cfcomponent>

Unfortunately, all the docs either explain cfinvoke really well, but don’t mention cffunction, or vice versa. I’m sort of lost.

Are you getting an error?

I noticed that you’re saying that your returnType=“string” but you’re not returning anything. You’ll need to get your string from that query and use <cfreturn /> to output it to the return variable “foo” you declared in the <cfinvoke>


On a side note have a look at createObject(). Personally I find it a lot tidier than cfinvoke


<cfset foo = createObject('component','addpage').add(somevar) />

Single line and does exactly the same thing.

Well done on getting into CFC though ;). Persist with them as they’ll make things a lot easier for you and get you out that spaghetti code hell that is single pages and includes.

I noticed that you’re saying that your returnType=“string” but you’re not returning anything. You’ll need to get your string from that query and use <cfreturn /> to output it to the return variable “foo” you declared in the <cfinvoke>

I agree the function isn’t returning anything. But do you actually want to return anything from the function? It’s not required.

If you don’t want to return anything, the function returnType should technically be “void” (ie “returns nothing”)

[INDENT]<cffunction … returntype=“void”>
[/INDENT]

Then in the cfinvoke, you don’t need to define “returnVariable”. Technically you can. It won’t cause an error. But the variable won’t be defined. So it serves little purpose.

[INDENT]<cfinvoke component=“addpage” method=“add”>

</cfinvoke>
[/INDENT]

<cffunction name=“add” access=“public” returntype=“string”>
<cfargument name=“foo” type=“string” required=“true”>
<cfset bar = #arguments.foo#>
<cfquery name=“addpage” datasource=“hepoffice”>
INSERT into table (col1)
VALUES (#bar#)
</cfquery>
</cffunction>

A few tips to improve the function.

  • Don’t forget to VAR scope any function local variables, including query names.
  • Also, don’t have to assign arguments.foo to another variable to use it. Just use arguments.foo directly in the query
  • Use cfqueryparam :slight_smile: Change the cfsqltype as needed.

Not tested


<cffunction name="add" access="public" returntype="string">
     <cfargument name="foo" type="string" required="true">
     <cfset VAR addpage = "">
     <cfquery name="addpage" datasource="hepoffice">
        INSERT into table (col1)
        VALUES ( 
            <cfqueryparam value="#arguments.foo#" cfsqltype="cf_sql_integer">
        )
     </cfquery>
</cffunction>

I forgot to remove the returntype=“string” in the function:


<cffunction name="add" access="public" returntype="void">
     <cfargument name="foo" type="string" required="true">
     <cfset VAR addpage = "">
     <cfquery name="addpage" datasource="hepoffice">
        INSERT into table (col1)
        VALUES ( 
            <cfqueryparam value="#arguments.foo#" cfsqltype="cf_sql_integer">
        )
     </cfquery>
</cffunction>

I’m an idiot. The reason it wasn’t working was because the row already existed in the database. :headbang: I deleted it and re-ran the app, and it worked fine.

@Starlight: I always use <cfqueryparam, but usually omit it from my pseudocode to reduce clutter. In this case, #bar# is not user input, but the result of a CGI variable.

btw, what’s the advantage to using VAR in this example?

@Clark: I’ll definitely try to learn more about createObject(). Anything to make things simpler.

var makes the variable private to that function.

Yep I get that much. Just wondering how that helps. Better for memory usage? Faster?

Yep I get that much. Just wondering how that helps. Better for memory usage? Faster?

Safer code. If you don’t var scope, you can unintentionally overwrite other variables outside the function. It can happen even with a single page. But it’s especially if you store components in a shared scope, because they can be accessed by multiple threads. If you don’t keep the variables for each thread separate, one thread may overwrite the variables of another (race conditions). That creates all sorts of crazy bugs and behavior. ie ThreadA can end up getting the results intended for ThreadA, get an error, etc…

That is allowed, but it sortof breaks encapsulation. Usually the recommendation is to pass it into the function, as an argument, rather than referencing it directly.

ie ThreadA can end up getting the results intended for ThreadA, get an error, etc…

ThreadA can end up getting the results intended for ThreadB! :wink: