How to call a function from another function using the cfc object reference?

Sorry for the sentence phrase. I could not find a better way to describe this. But my problem is this:

I have 3 cfc, namely settings.cfc, prices.cfc and helpers.cfc. These cfcs extend the 4th cfc.cfc controller. Helper.cfc is as follows:

<cfcomponent extends="Controller"> <cffunction name="formatCurrency"> <cfset formattedCurrency = 1 /> <cfreturn formattedCurrency> </cffunction> <cffunction name="processTemplateVariables"> <cfargument name="templateText" default="defaultText" > <cfset formatCurrency() /> <cfreturn formattedCurrency > </cffunction> </cfcomponent> 

The settings.cfc parameter has a setApplicationVariables method, which we use to set application-level variables. In this cfc, I created the helpers.cfc object and placed this object in the application area. The settings.cfc parameters are as follows:

 <cfcomponent extends="Controller"> <cffunction name="setApplicationVariables"> <cfset application.helpers = createObject("component","controllers.Helpers") /> </cffunction> </cfcomponent> 

The settings.cfc parameter is set when the application starts, which, in turn, creates the helpers.cfc object and places it in the application area. We create a reference to the ProcessTemplateVariables method in the .cfc controller as follows:

 <cfcomponent extends="Wheels"> <cfset getFormattedCurrency = application.helpers.processTemplateVariables > </cfcomponent> 

In price.cfc, we use this link to call the function processTemplateVariables that it does. But it does not call the function formatCurrency , which is called internally from processTemplateVariables and throws an error " formatCurrency variable - undefined ".

But if I use application.helpers.processTemplateVariables(templateText="someText") , it works.
It also works when I use cfinvoke as below:

 <cfinvoke method="processTemplateVariables" component="controllers.helpers" templateText="someText" returnvariable="content"> 

.Cfc prices are as follows:

 <cfcomponent extends="Controller"> <cffunction name="index"> <!--- does not work, throws 'the formatCurrency() variable is undefined' ---> <cfdump var="#getFormattedCurrency("someText")#"><cfabort> <!--- works ---> <cfinvoke method="processTemplateVariables" component="controllers.helpers" templateText="someText" returnvariable="content"> <!--- works ---> <cfset application.helpers.processTemplateVariables("someText") /> </cffunction> </cfcomponent> 

I am not sure why using the link does not work. Sorry for the earlier confusion, but your comments made me dig deeper, and I could find out that it was a link that was the culprit. Is there any way to make this work a reference, would that be cool?

+5
source share
2 answers

Update:

This blog post (from Adam Cameron) has a better description. Summarizing:

.. it pulls the method from CFC, so it will work in the context of the calling code, not an instance of CFC. Depending on the code in the method, this may or may not matter.

In your particular case, it matters. The function has a dependency on formatCurrency , which does not exist in the "context" of the calling page, and that is why you get an "undefined" error.


(From comments)

Yes, I’m sure you cannot do this. Each function is compiled into a separate class: a specifically static inner class . (You can see the names of the inner classes if you upload the function name without brackets, i.e. #application.helpers.formatCurrency# ). In other words, it disconnects from any particular instance - and by extension - of other functions.

When you create an instance of a component, all functions are stored in the variables . Therefore, when you call "processTemplateVariables" - from within the instance - it has access to other functions through the scope of the variables component. When your code creates a link to this function, what you actually get is completely disconnected from the parent instance, i.e. application.helpers . Thus, he will not have access to any of the other functions. Therefore, why are you getting the "undefined" error.

+2
source

The limitation is well understood from Leigh's answer.

To focus on your requirement here: using the short name alias for functions, you can still use your source code with a little trick of adding all the dependent functions as a reference so that they are accessible inside the controller.cfc area, similar to getFormattedCurrency .

Change 1:

 <cfcomponent extends="Wheels"> <cfset getFormattedCurrency = application.helpers.processTemplateVariables /> <cfset formatCurrency = application.helpers.formatCurrency /> </cfcomponent> 

Now, for the fun part, it is quite possible to access the function from another cfc and save all the dependencies. I was also surprised when I remembered Bennadel's amazing post here . This is just awesome. But to warn you , this practice is not recommended . So I started setting up and still went ahead. And all this worked like a charm without any problems that we have encountered so far (but I am quite sure that some complications may arise). The point of the problem with the original use was that the function has a dependency on formatCurrency, which does not exist in the "context" of the calling page, since it got Leigh in its answer. So, if you can simply copy objects with a scope or even functions from another component in you controller.cfc , it sounds strange and amazing at the same time, but you can use the <cfinclude> inside the .cfc controller (note: not recommended) based on the idea that Bennadel is used as an example.

Edit2:

Your .cfc controller should look something like this:

 <cfcomponent extends="Wheels"> <!--- Placed inside the controller scope itself, outside every other function ---> <cfinclude template="helpers.cfc" /> ....<rest of your code>.... ........... </cfcomponent> 

Note that you don’t even need to create short hand aliases for functions. All components and views can directly use the function name as you planned. There is no need to indicate that there would be a chance of naming collisions if any other component that extends Controller.cfc has a function with the same name as any function inside the imported component library. But this can be solved by following more specialization for functions on several components, or as simple as using a prefix as part of the coding standard for function names to avoid such future scenarios.

+1
source

Source: https://habr.com/ru/post/1208878/


All Articles