How to initiate the multiple cfc with one object? - coldfusion

I have one project folder. Inside the project folder is one Application.cfc, one index.cfm and a folder of cfc's:
/ProjectFolder
--- Application.cfc
--- index.cfm
--- cfc (folder)
SomeComponent.cfc
OtherComponent.cfc
...
In the cfc folder, I have 10 *.cfc files. How can I initiate, or map, the 10 *.cfc files with the one object in ColdFusion?

If any of the CFCs can be created once and only once, meaning that they do nothing more than call stored procedures, contain algorithms or other business logic, then you can simply create those CFCs as application scoped variables when the application first starts.
In this example, Application.cfc is in the root folder and the CFC files are in the /cfc/ folder.
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfset application.stObject = {
foo = new cfc.Foo()
, bar = new cfc.Bar()
, etc = new cfc.Etc()
} />
<cfreturn true />
</cffunction>
Then, anywhere in your code, you can reference a particular CFC and call a function in it like so:
<cfset qMyData = application.stObject.foo.getMyData() />
If you need to populate a CFC with data and carry it around though a user's session, you would want to create that object using onSessionStart() in Application.cfc. You can also create it at the point that you need to populate it and place it into session instead of carrying around an empty version that never gets used.
Finally, you may need to just create certain of those CFCs as needed for the life of the page request only. Those would be created in the variables scope and populated at some point during the request and would be removed once the request has completed.

Related

Should I place a DSN (datasource) definition inside or outside onApplicationStart() function?

When is it appropriate to place DSN definitions inside the onApplicationStart() function vs outside of the function?
I have seen this method:
<cfset this.datasource = "datasource_name">
<cffunction name="onApplicationStart" returnType="boolean" output="false">
and I've seen it this way...
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfset application.dsn = "datasource_name">
The only reasons I can find for this format is leaving the datasource outside the function is an older, still supported, but outdated way of doing things.
Is there any other reason for it?
I did find this question already, but it only states where DSNs should be declared, but not when to it should go inside vs outside.
Q: Should I place a DSN (datasource) definition inside or outside onApplicationStart() function?
A: Outside
That way <cfquery>, QueryExecute(), and ORM can tap into that datasource information without that information being repeated.

Method cannot be found when invoking Webservice API

While invoking the Webservice API for the GetTablesBin method, I'm getting the error Web service operation GetTablesBin with parameters cannot be found.
Webservice Calling code
<cfinvoke
webservice="http://www.argusmedia.com/ArgusWSVSTO/ArgusOnline.asmx?wsdl"
method="GetTablesBin"
returnvariable="binResponse">
<cfinvokeargument name="authToken" value="#AuthToken#"/>
<cfinvokeargument name="tableNames" value="#tablename#"/>
</cfinvoke>
I can see the method running fine using the SOAPUI client.
While digging further, found the method class to be missing in the Coldfusion stubs folder as well.
Any pointers would be really helpful?
Web service operation GetTablesBin with parameters
{...} cannot be found.
Notice it says "with parameters"? Subtle difference, but it either means a) the method does not exist at all OR b) it does exist, but is receiving the wrong number or type of arguments. In this case the problem is "b)".
When troubleshooting web service issues, it is often helpful to create an instance of the web service, then dump that object to see which arguments the method requires. According to CF11, the "GetTablesBin" method expects two arguments: a String and an ArrayOfString. However, the current code passes in two String's. Hence the error.
Code:
<!--- Add {refreshWSDL=false} if needed --->
<cfset ws = createObject("webservice"
, "http://www.argusmedia.com/ArgusWSVSTO/ArgusOnline.asmx?wsdl")>
<cfset writeDump(ws)>
Dump:
An ArrayOfString is a slightly strange beast:
... there is no direct mapping of ArrayOfString. So it is essentially
treated as a structure, just like any other complex type. If you look
at the wsdl, ArrayOfString contains a single key named string, whose
value is an array of type="s:string":
To resolve the error, simply create a structure with the proper key and pass it into the cfinvoke call. (Though personally I prefer createObject() which is a little less bulky IMO)
<cfset arrayOfStrings = ["tableName1","tableName2"] />
<cfset tableNames.string = arrayOfStrings />
<cfinvoke ....>
<cfinvokeargument name="authToken" value="#AuthToken#"/>
<cfinvokeargument name="tableNames" value="#tableNames#"/>
</cfinvoke>

How to reinitialize the website in Application.cfm file scope

Maybe the Title seems bit odd, but my question is straight, how can reinitialize the application with Application.cfm, i know how we do in Application.cfc like
<cfscript>
if(structKeyExists(url, 'reinit')) {
onApplicationStart();
}
</cfscript>
But how in Application.cfm, not sure, please guide
Thanks
Firstly, running onApplicationStart() no more restarts the application than running an onClick() mouse-click event handler causes your mouse button to depress. onApplicationStart() is called as a result of the application starting, not the other way around.
Secondly, Application.cfm has nothing to do with the application lifecycle, it is merely a CFML file that is included at the beginning of every request. it is more closely associated with onRequestStart() than onApplicationStart(): the file is, unfortunately, misnamed. Its counterpart onRequestEnd.cfm demonstrates this.
I presume your requirement here is to re-initialise your application scope, yes? Do you have all your application-scope setting isolated in a specific CFML file, eg: applicationSettings.cfm, and then have logic like this in your Application.cfm:
// Application.cfm
if (!structKeyExists(application, "inited")){
include "applicationSettings.cfm";
}
(then as a last thing in applicationSettings.cfm set application.inited to true).
If so you simply need to modify your condition to include your URL reinit variable, eg:
if (!structKeyExists(application, "inited") || structKeyExists(URL, "reinit")){
include "applicationSettings.cfm";
}
In OnRequestStart() put something like this:
param name='url.reloadApp' default='no';
if(url.reloadApp == 'yes')
{
applicationStop();
}

Cannot get mappings to work

I have the following directory structure:
| SITES_FOLDER
|___ WEBSITE1
|___ WEBSITE_CFC
|___ CFC_DIR
WEBSITE1 contains an Application.cfc and some pages. Then I have a component ShoppingCart.cfc inside the WEBSITE_CFC directory that is instantiated on session start using this code:
createObject("component","WEBSITE_CFC.ShoppingCart").Init() />
This works.
Now I move ShoppingCart.cfc to the CFC_DIR directory and change my instantiate code to:
createObject("component","CFC_DIR.ShoppingCart").Init() />
Obviously this does not work because ColdFusion searches for a "CFC_DIR" directory under the root directory "WEBSITE1" and doesn't find it.
I thought this problem would be solved by using mappings so I go to the CFIDE administrator. Server Settings > Mappings.
Logical path: "CFC_DIR"
Directory path: "C:\some\folders\SITES_FOLDER\CFC_DIR"
No luck. So then I tried in Application.cfc:
<cfset THIS.mappings["/CFC_DIR"] = "C:\some\folders\SITES_FOLDER\CFC_DIR" />
This did not work either!
EDIT:
Maybe I understand: if I try to create the CFC from a cfm template, it works.
The error comes up when I try to create it inside the OnSessionStart Application.cfc's method:
Ensure that the name is correct and that the component or interface
exists. Message Could not find the ColdFusion component or interface
C:\some\folders\SITES_FOLDER\WEBSITE1|WEBSITE_CFC\ShoppingCart.cfc.
In other words, it keeps looking for it in the wrong dir.
WHY?
If you're changing the file to /CFC_DIR but it's still using /WEBSITE_CFC it sounds like the cache needs clearing.
Clear the Cache in CF Admin
Clearing the cache can be done manually in the ColdFusion Administrator. After login, the third item in "Server Settings" is "Caching". Scroll to the bottom of the page for buttons to clear the cache.
For development purposes you may want to consider disabling the various caching options on this page entirely - they can be useful for performance improvement on live servers, but are generally an unnecessary hindrance on your development machine.
Clear the Cache Programmatically
If you have an automated deployment, you don't want to have to login to the CF Admin on remote servers and press buttons. Fortunately, you can also clear the cache programmatically:
<cfscript>
createObject("Component", "cfide.adminapi.administrator")
.login("**replace with admin password**");
RuntimeService = createObject("component", "cfide.adminapi.runtime");
// Clear whole cache:
RuntimeService.clearTrustedCache();
// Clear cache for individual files:
RuntimeService.clearTrustedCache("/path/to/file1.cfm,/path/to/file2.cfm");
// Clear component cache:
RuntimeService.clearComponentCache();
</cfscript>
(Code adapted from Charlie's blog entry.)
The API for the Admin Runtime component can be found at http://www.cfexecute.com/admin-api-documentation/runtime-cfc/

Read Application.DataSource in CF9

How can I read the default application.datasource from my code?
A dump of application does not show me the datasource, and trying to read application.datasource gives an error.
Try dumping application.getApplicationSettings()
Try re-start the applciation. You can't just dump application and see the datasource. But if you have this set in application.cfc it "should" be working.
component output="false" {
this.name = "MyDemo";
this.datasource = "DemoDB";
}
Edit: Nice Tony I didn't know that.
The this scope in the Application.cfc only persists for the duration of the onApplicationStart(), onSessionStart() onRequestStart() etc.
If you want to expose variables, in your onApplicationStart(), simply store the in the application scope.
application.myVariable = myVariable;