Copy link to clipboard
Copied
I have 2 cfcs...one of them contains some query functions that will need to be available to another cfc.
How do I make an object available to another CFC?
Do I create an init() function at the top and chain it to the CreateObject?
I've been developing in CF for about a year and half now and just now have started to realize the value of CFCs, having to learn some fundamentals. I'm not even sure I asked my question right...haha
Thanks,
Paul Ferree
Copy link to clipboard
Copied
You could <cfinvoke> it into a variable inside the calling cfc and use it, check out the livedocs on <cfinvoke>, or as you suggest you could createobject() it as well. Just like you call a .cfc in a .cfm file your .cfc files can call them the same way.
Copy link to clipboard
Copied
Another alternative is to use composition in your CFC. That is, you would create a property in your CFC that is the other CFC. You can then call that CFC via the property. There's nothing wrong (on any level) with taking GrumpyJoe's approach and calling cfinvoke or createObject. I just wanted to throw this out since you mentioned that you were just getting started with CFCs.
Following is some code to illustrate:
First, the component with the query functions. Let's say it's called (named) QueryCfc.cfc and that it lives in the same folder/directory as the second CFC (below).
<cfcomponent>
<cffunction name="get" access="public" returntype="query">
<cfquery name="myQry" datasource="dsn">
select * from my_table
</cfquery>
<cfreturn myQry />
</cffunction>
<cffunction name="set" access="public" returntype="query">
<cfargument name="val1" type="string" required="true" />
<cfargument name="val2" type="string" required="true" />
<cfquery name="myQry" datasource="dsn">
insert into my_table( col1, col2 )
values( '#arguments.val1#', '#arguments.val2#' )
</cfquery>
<cfreturn myQry />
</cffunction>
</cfcomponent>
The other CFC, which will use the function in the above.
<cfcomponent>
<!--- if the file, QueryCfc lived in another directory, you'd need to change the type attribute to reflect that path, using the dot notation, such as webroot.folder1.folder2.QueryCfc --->
<cfproperty name="queryCFC" type="QueryCfc" default="" />
<cfscript>
queryCFC = createObject("component", "QueryCfc");
</cfscript>
<cffunction name="doSomething" access="public" returntype="void">
<cfset myRecordSet = queryCFC.get() />
<!--- do stuff with the record set --->
<cfreturn />
</cffunction>
<cffunction name="doSomethingElse" access="public" returntype="void">
<cfset queryCFC.set('value1','value2') />
<!--- do other stuff --->
<cfreturn />
</cffunction>
</cfcomponent>
The second CFC is composed of (has) an instance of the first CFC. With composition, the first CFC (QueryCfc) is created one time, when the second CFC is instantiated, and then can be used throughout the CFC where needed.
Again, both approaches (among others still) will work but thought you might like to see an additional way to accomplish the same result with CFCs.
Good luck!
Copy link to clipboard
Copied
I beleive that Grump Joe gave you the likely answer as I understood your question.
You can invoke a componet in another compent exactly the same as invoking it an any other CFML code with any of the available methods, <cfinvoke...>, createObject(), <cfobject...>, etc. In Object Orientated language this is know as compisiting, I.E. one object using another object as a member property.
You can also utilize OO inhertance concept with the "extends" property of the <cfcomponent...> tag. I do not beleive that is the solution to the problem you stated, but it is a concept of which to be aware.
Copy link to clipboard
Copied
I know I can CreateObject inside a function within a CFC, but how do I instantiate it in a way where I can reference that object throughout the rest of the CFC without doing a CreateObject in each function it uses...I thought I had to initialize it first or something.
I don't think I understand the extend concept either...I tried it but it wasn't working.
Paul
Copy link to clipboard
Copied
Sorry. This one posted but did not include the files. Please disregard and see next post.
Copy link to clipboard
Copied
Paul,
It's through composition that you'll be able to instantiate it once and use it throughout the CFC. Ian and I both mentioned composition in our replies and this is what my code sample above uses.
To try and help I've attached a 3 files (index.cfm.txt, cfc1.cfc.txt, cfc2.cfc.tx -- rename them so that the .txt extension is removed before trying to run them). If you place them all in the same directory on your CF web server (any directory that's accessible by CF), you should be able to access the index.cfm page and see the output "Hello World" in your browser. I tested on my local machine to verify that it works.
The basic gist is this:
1. Create your base CFC (cfc1) that has the functions you want to access in your other CFC (cfc2)
2. In the same directory/folder (for now), create the other CFC (cfc2), using the cfproperty tag to create a property that is the other CFC (cfc1)
3. Create a script block below the cfproperty tag to instantiate the CFC (cfc1).
4. Use cfc1 in cfc2 willy-nilly!
Hopefully the attached code, even though it's incredibly basic, will help illustrate the process for you!
Copy link to clipboard
Copied
Note that the <cfproperty...> tag has a 99% chance of being uncessary.
The idea behind using the <cfproperty...> tag is to allow fancier uses of CFML components as web services and flash remote object for FLEX code. But otherwise serve little or no purpose.
Copy link to clipboard
Copied
Awesome....
I guess I was just under the impression that if I set a variable in the CFC constructor area that it wouldn't be availble to the other methods in the CFC. I think I mistook that with the real issue that you can't pass values directly to a CFC to be used in the subsequent functions...that's where an init() function would come into play...going back and rereading my "bird book" I think I got it now.
Thanks for dealing with my shortsidedness!! You guys always set me straight on this forum!
Paul
Copy link to clipboard
Copied
paulferree wrote:
I think I mistook that with the real issue that you can't pass values directly to a CFC to be used in the subsequent functions...that's where an init() function would come into play...
Any code you set outside a <cffunction...> block AKA the "pseudo constructor" will be run when the component is initialized. But there is no way to pass parameters to this code to be used during such initialization. Thus was born the common practice of an init() function.
I have heard rumors that version 9, currently in early testing, will have a true constructor function that one would presumably be able to pass parameters into.
Copy link to clipboard
Copied
Where you instinate the component determines how global it is in the larger component. There are three main scopes inside a component going from the most private to most public there are the 'unamed' function local scope the variables scope that is local to the entire component to the 'this' scope that is public to all code inside and outside the function.
<cfcomponent ...>
<cfset variables.myCompositeObjA = createObject(...)> <!--- this object can be used in any code inside this component ...>
<cfset this.myCompositeObjB = createObject(...)> <!--- this object can be used in any code inside or outside this component. --->
<!--- P.S. the THIS version would be a very bad practice to use for 99.9 percent of the cases --->
<cffunction ...>
<cfset var myCompositeObjC = createObject(...)> <!--- this object can only be used inside this function--->
Copy link to clipboard
Copied
I got a question from this theme about how to implement multy cfc infrastructure and maximize perfomance.
I have 1 cfc that has all my functions (~2000 lines) for one application. For the simplicity at the early stages of development I put them all in one cfc and now I can't find myself in it and also when I make changes to one function it take some time to compile so I could see the results. I want to separate functions by their specialty into several cfcs.
I create object in Application.cfm this way:
<cfset myObj = createObject(main.cfc)>
What is the right way to call functions contained by secondary cfcs from the main.cfc so I only have to wait until the changed cfc compiles?
thanks a bunch
Copy link to clipboard
Copied
Best way to do it for me would be to make cfc 2 inherits cfc1. So every properties and methods of cfc1 are available in cfc2 using the super keyword
Example of cfc1
<cfcomponent>
<cffunction name="myFunction" access="public" returntype="string">
<cfreturn "hello from component 1"/>
</cffunction>
</cfcomponent>
In cfc2
<cfcomponent extends="cfc1">
<cffunction name="callCfc1Function">
<cfset theString = super.myFunction()/>
</cffunction>
</cfcomponent>
Hope it helps
Damien