5

I am currently using the <cfinvoke> tag to invoke CFCs and pass them arguments. This is really convenient because I can use tags to pass in only the parameters that I want like such:

<cfinvoke component="pathtofolder.imagehandler" method="SomeMethod" argumentcollection="#VARIABLES#" returnvariable="ImageHandlerResult">
<cfif structkeyexists(ARGUMENTS, 'Argument1')>
<cfinvokeargument name="Parameter1" value="#ARGUMENTS.Argument1#" />
</cfif>
<cfif structkeyexists(ARGUMENTS, 'Argument2')>
<cfinvokeargument name="Parameter2" value="#ARGUMENTS.Argument2#" />
</cfif>
<cfif structkeyexists(ARGUMENTS, 'Argument3')>
<cfinvokeargument name="Parameter3" value="#ARGUMENTS.Argument3#" />
</cfif>
</cfinvoke>
<cfreturn ImageHandlerResult /> <!--- how do you get this using createObject/new method? --->

If I use the new() or createObject() methods to create an instance of the CFC and then call the methods within this newly created instance I'm not able to conditionally pass arguments. I get errors at runtime.

<cfset ImageHandler = new pathtofolder.imagehandler()/>
<cfset ImageHandler.SomeMethod(
    <cfif StructKeyExists(ARGUMENTS, 'Argument1')>
    Parameter1 = ARGUMENTS.Argument1
    </cfif>
    <cfif StructKeyExists(ARGUMENTS, 'Argument2')>
    Parameter2 = ARGUMENTS.Argument2
    </cfif>
<cfif StructKeyExists(ARGUMENTS, 'Argument3')>
    Parameter3 = ARGUMENTS.Argument3
    </cfif>
)/>

How can I pass in arguments conditionally using the above method? Should I use the cfinvoke method on the new instance - in which case what is the point in making an instance and then using cfinvoke again when I could just stick to using cfinvoke on the actual CFC directly?

James A Mohler
  • 10,562
  • 14
  • 41
  • 65
volume one
  • 5,494
  • 7
  • 39
  • 101
  • Are you calling `cfinvoke` inside another function? If not, there isn't really a true `arguments` scope. You're creating a structure named `arguments`. And I believe, since it's a structure, you may also run into pass-by-reference issues. – Shawn Oct 30 '18 at 18:09
  • Are you calling this from inside a function? – Shawn Oct 30 '18 at 19:14
  • Yes I am @Shawn. It occurs within a CFC that takes processes posts submitted by a user. See here https://stackoverflow.com/questions/53064456/should-i-use-cfinvoke-or-something-else-to-call-a-cfc-multiple-times/53068303#53068303 – volume one Oct 31 '18 at 09:13

2 Answers2

6

You can use argumentCollection. Argument collection is a structure and each key will be deconstructed as individual arguments.

<cfset ImageHandler = new pathtofolder.imagehandler()>
<cfset args = {}>
<cfif StructKeyExists(ARGUMENTS, 'Argument1')>
  <cfset args.Parameter1 = ARGUMENTS.Argument1>
</cfif>
<cfif StructKeyExists(ARGUMENTS, 'Argument2')>
  <cfset args.Parameter2 = ARGUMENTS.Argument2>
</cfif>
<cfif StructKeyExists(ARGUMENTS, 'Argument3')>
  <cfset args.Parameter3 = ARGUMENTS.Argument3>
</cfif>

<cfset ImageHandler.SomeMethod(argumentCollection=args)>
rrk
  • 14,861
  • 4
  • 25
  • 41
  • Thanks for this. But I already use `argumentCollection` to pass the Variables scope variables. How would I pass both variables scope and arguments? – volume one Oct 30 '18 at 17:25
  • Your example does not show that you are passing in argumentCollection, so I’m not sure what you’re referring to when you say you are. Also, you may want to look at using optional arguments in your method definition, which can be assigned a default value. – Redtopia Oct 30 '18 at 17:48
  • Once i have ran `` how do I `` the result back to the calling page? If use '' I get a 'returnvariable' that I place in a '' and send it back to the caller – volume one Oct 30 '18 at 17:56
  • 3
    Your returned value will be in `myReturnValue` for `myReturnValue = ImageHandler.SomeMethod(argumentcollection=args)`, provided your `SomeMethod()` has a `return`. – Shawn Oct 30 '18 at 18:08
  • @Shawn thank you. so it should be `` right? – volume one Oct 30 '18 at 18:22
  • Yes. And then `ImageHandlerResult` would hold the return valued of `SomeMethod()`. But make sure that `SomeMethod()` actually returns what you want. – Shawn Oct 30 '18 at 18:48
  • @Shawn yes I have wrapped ImageHanderResult in a cfif tag to check if the structkeyexists and if it has a len() before returning it. – volume one Oct 30 '18 at 18:56
  • 1
    You want to make sure it returns something every time, and if you need to, check for existence further down the workflow. – Shawn Oct 30 '18 at 18:59
1

There is a similar way which can be used to pass conditional attributes to ColdFusion tags. Following is an example for a <cfmail> tag.

<cfset local.cfmailArguments = {
  to : 'toemail@test.com',
  from : 'email@test.com',
  subject : 'Passing custom smtp',
  type : 'html',
}>
<!--- There are custom mail settings available in session.SMTPDetails --->
<cfif structkeyexists(session, "SMTPDetails")>
  <cfset local.cfmailArguments['from'] = session.SMTPDetails.FromEmail>
  <cfset local.cfmailArguments['server'] = session.SMTPDetails.Server>
  <cfset local.cfmailArguments['username'] = session.SMTPDetails.UserName>
  <cfset local.cfmailArguments['password'] = session.SMTPDetails.Password>
  <cfset local.cfmailArguments['port'] = session.SMTPDetails.Port>
  <cfset local.cfmailArguments['usetls'] = session.SMTPDetails.TLS>
  <cfset local.cfmailArguments['usessl'] = session.SMTPDetails.SSL>
</cfif>
<cfmail attributecollection="#local.cfmailArguments#">
  Your mail content.
</cfmail>

Instead of having to manage different tags in each conditions.

rrk
  • 14,861
  • 4
  • 25
  • 41