Paul asks:
So Paul, you already have the right answer, a proxy CFC. But you do not need to hard code the DSN value at all. Let's look at a real, simple example. First I'll build the main CFC, Paris:I am working with CF8 and cfajaxproxy. I have all of my cfc's in the application scope and they all have init functions that take the dsn as parameters. On a form that I have, I am using cfajaxproxy to allow a user to add a value to a 'type' drop down list and the functions to do this are in my cfcs that I put in the application scope with variables.dsn.
I want to do something like this:
This isn't working because the cfajaxproxy call returns an error saying that 'element dsn is undefined in variables'.
I had to revert using this:
And changed the component to use application.dsn instead of variables.dsn Is there anyway to tell cfajaxproxy to use the application scope component (tried some things to no avail)? Or am I going to have to create a interface/facade (cfc that hits the app scope cfc) to do this? But I'm thinking that even if I do this, I'm going to have to hard code the variables.dsn to be the value of appllication.dsn or just use application.dsn within this new component.
<cfcomponent>
<cffunction name="init" access="public" returnType="paris" output="false">
<cfargument name="dsn" type="string" required="true">
<cfset variables.dsn = arguments.dsn>
<cfreturn this>
</cffunction>
<cffunction name="getBooks" access="public" returntype="query" output="false">
<cfset var q = "">
<cfquery name="q" datasource="#variables.dsn#">
select id, title
from books
</cfquery>
<cfreturn q>
</cffunction>
</cfcomponent>
This CFC is then set into the Application scope via onApplicationStart():
<cfset application.dsn = "tmz">
<cfset application.paris = createObject("component", "paris").init(application.dsn)>
So far so good. Now what would the proxy CFC look like? First off it is important where you place the proxy CFC. In order for the Ajax-based controls to use them, they must be under web root. Your main CFCs can be anywhere - but the proxies must be web accessible. Let's build a simple proxy component to integrate with Paris' getBooks() method:
<cfcomponent output="false">
<cffunction name="getBooks" access="remote" returnType="query" returnFormat="json" output="false">
<cfreturn application.paris.getBooks()>
</cffunction>
</cfcomponent>
Some things to note. The method is marked remote. Without that, I wouldn't be able to run the method even if it was under web root. I also went ahead and supplied a returnFormat. ColdFusion's Ajax controls will do this for me, but it doesn't hurt to specify it here as well. Then I just hit the Application scoped CFC. Note that I'm not worrying about the DSN setting.
I can see one possible thing here that could concern you. Imagine your proxy grows rather large and you have quite a few methods. Now imagine all of a sudden you changed the Application variable "paris" to "parisCFC". All of those methods would then break. You could get around this by adding a utility method:
<cfcomponent output="false">
<cffunction name="getBooks" access="remote" returnType="query" returnFormat="json" output="false">
<cfreturn getParis().getBooks()>
</cffunction>
<cffunction name="getParis" access="private" output="false">
<cfreturn application.paris>
</cffunction>
</cfcomponent>
In this sample, I added a method named getParis. Any method that needs Paris would simply call that first, and then call the method, as you see in getBooks above. I also marked getParis private since it doesn't make sense to remotely expose that.
Archived Comments
Thanks for the reply. I ended up setting a variable in the proxy cfc to be the object of the cfc that i wanted to call the functions from:
variables.itemManager=createObject("component", "itemManager").init(APPLICATION.dsn);
then i wrote functions in the proxy cfc like this:
<cffunction access="remote" name="getAllItemTypes" returntype="query" output="true">
<cfreturn variables.itemManager.getAllItemTypes() /> </cffunction>
What do you and others think?
I think that if you have more than a handful of remote methods, you should
a) look at ColdSpring/LightWire for managering your dependancies and properties
b) look at AOP-like solutions, such as ColdSpring's RemoteFactoryBean for writing the proxy 'service' CFC for you.
Hi Ray,
I have set up a quick demo app just like above, I have a proxy CFC that talks to the application scoped object (well that’s the idea), but when I hit the application scoped object inside the proxy cfc I get the cf error "Element DBACCESS is undefined in a Java object of type class" etc... I can't for the life of me see whats going on here. I can send you the sample files if you want. Are there any settings I need to enable to allow the proxy CFC to access application scoped objects? This is driving me mad. Here is the simple proxy function call
<!--- Get array of media types --->
<cffunction name="getMedia" access="remote" returnType="array">
<cfreturn application.dbAccess.getMedia()/>
</cffunction>
I am setting up the application scoped object like this in the application.cfc
<cfset application.dbAccess = createObject("component","model.dbaccess").init(dsn='cfartgallery')/>
You are using application.dbAccess, and it doesn't exist. Your code needs to create this value somehow, somehwere. I can't say exactly how as I don't know the rest of your code.
Ray,
I am creating the application.dbaccess object in the onApplicationStart() in my application.cfc using this line
<cfset application.dbAccess = createObject("component","model.dbaccess").init(dsn='cfartgallery')/>
I'm i doing something really stupid here an just can't see it
Cheers
Simon
Is your CFC under the same folder that your Application.cfc is in?
I'm getting the same problem that Simon had. Any resolution?
Can you show (via pastebin) your Application.cfc?