I've a variable in my Application.cfm that stores the datasource for cfqueries.
<cfset mydatasource= 'somedatasorce'>
I can use it in any normal cfm page as below:
<cfset any_var = #mydatasource#>
I've a cfm page that calls a cfc which builds a query dynamically. This is the URL Invocation Method of CFC.
I'm not able to access "mydatasource" in the CFC using the above statement. It says "mydatasource" is undefined. I tried storing this in Application scope & accessed in CFC but again it says "mydatasource" is undefined in "Application".
On a bit of search, I found that the CFC needs to be instantiated in order to access the Application scope. But the URL Invocation method doesn't create an instance.
I can pass the datasource using query string but I'm looking for a better & more secure alternative.
Any suggestions are highly appreciated.
Thanks!! :)
I have been adding a number of ajax calls to an old application here and in order to get some application specific settings I created a file I called App.cfc. The contents of it are simply:
<cfcomponent>
<cfscript>
this["datasource"] = "something";
..... and so on .....
</cfscript>
</cfcomponent>
Then the CFC files I am making my URL calls to they simple extend App. So within those CFCs I can do datasource="#this['Datasource']#"
May not be the most "pretty" of ways to get the job done but it has been working here without issues.
UPDATE
I should have also mentioned that in order to avoid having settings in both that CFC and in the Application.cfm, I have something like this in my Application.cfm:
<cfscript>
objApp = CreateObject("component", "Components.App");
StructAppend(App, objApp);
</cfscript>
These old applications I am working with have a structure withing VARIABLES called App that is a copy of all Application variables. I see no reason why in this case you could not just do a structure appending to VARIABLES since appears that is where you are expecting things like the datasource to be on in your CFM pages.
Related
In our Portal application.cfc, we are defining (setting up) our DSN connections like so:
<cfset this.datasource = "DSN1"> (Main DB)
<cfset this.datasource_1 = "DSN2"> (2nd DB)
<cfset this.datasource_2 = "DNS3"> (3rd DB)
These are in the tags. I have also moved then to the ‘OnApplicationStart’ function and cannot get it to work correctly.
This application.cfc if referenced in the main APP, that the other apps have access to (App2, etc…), my question is;
How do I reference the other datasources (this.datasource_2) in a query for the App2 application?
<cfquery name="queryname" datasource="**[What goes here]**"> For second datasource
The this.datasource DSN is always being referenced because there is no datasource listed in the cfquery tags.
Any help you can provide or links to send my way will be appreciated. Thanks in advance!
Try seeing additional application variables
<cfset application.datasource_1 = "DSN2"> (2nd DB)
<cfset application.datasource_2 = "DNS3"> (3rd DB)
My solution is to not use any variables at all and simply hard code the datasource names. In other words, for this:
<cfquery name="queryname" datasource="**[What goes here]**"> For second datasource
The answer is "DSN2".
In order for these datasources to be usable, they have to be defined on the server and you have to know their names. If you assign them to some sort of global variable, then you would have to know the name of that variable. I see no value to using global variables in this situation.
For DSN1, there are pros and cons to using a global variable. The advantage of a variable is that you don't need a datasource attribute for the queries that use this database. The disadvantage is that your code becomes a little less consistent if some queries have a datasource attribute and others don't. That topic is best discussed in person while drinking beer.
or you can use the Applicaton.cfc this.datasources struct
I have a “best-practices” question in regards to the correct way to instance CFCs that all need to talk to each other in a given project.
Let’s say for example you have a web application that has a bunch of different modules in it:
Online Calendar
Online Store
Blog
File Manager (uploading/downloading/processing files)
User Accounts
Each of these modules is nicely organized so that the functions that pertain to each module are contained within separate CFC files:
Calendar.cfc
Store.cfc
Blog.cfc
Files.cfc
Users.cfc
Each CFC contains functions appropriate for that particular module. For example, the Users.cfc contains functions pertaining to logging users on/off, updating account info etc…
Sometimes a CFC might need to reference a function in another CFC, for example, if the store (Store.cfc) needs to get information from a customer (Users.cfc). However, I'm not sure of the correct way to accomplish this. There are a couple ways that I've been playing with to allow my CFC's to reference each other:
Method 1: Within a CFC, instance the other CFC’s that you’re going to need:
<!--- Store.cfc --->
<cfcomponent>
<!--- instance all the CFC’s we will need here --->
<cfset usersCFC = CreateObject("component","users") />
<cfset filesCFC = CreateObject("component","files") />
<cffunction name="storeAction">
<cfset var customerInfo = usersCFC.getUser(1) />
This approach seems to work most of the time unless some of the instanced CFC’s also instance the CFC’s that instance them. For example: If Users.cfc instances Files.cfc and Files.cfc also instances Users.cfc. I’ve run into problems with occasional dreaded NULL NULL errors with this probably because of some type of infinite recursion issue.
Method 2: Instance any needed CFCs inside a CFC’s function scope (this seems to prevent the recursion issues):
<!--- Store.cfc --->
<cfcomponent>
<cffunction name="storeAction">
<!--- create a struct to keep all this function’s variables --->
<cfset var local = structNew() />
<!--- instance all the CFC’s we will need here --->
<cfset local.usersCFC = CreateObject("component","users") />
<cfset local.filesCFC = CreateObject("component","files") />
<cfset var customerInfo = local.usersCFC.getUser(1) />
My concern with this approach is that it may not be as efficient in terms of memory and processing efficiency because you wind up instancing the same CFC’s multiple times for each function that needs it. However it does solve the problem from method 1 of infinite recursion by isolating the CFCs to their respective function scopes.
One thing I thought of based on things I've seen online and articles on object oriented programming is to take advantage of a “Base.cfc” which uses the “extends” property of the cfcompontent tag to instance all of the CFC's in the application. However, I've never tested this type of setup before and I'm not sure if this is the ideal way to allow all my CFCs to talk to each other especially since I believe using extends overwrites functions if any of them share a common function name (e.g. "init()").
<!--- Base.cfc --->
<cfcomponent extends="calendar store blog users files">
What is the correct "best-practices" method for solving this type of problem?
If each of your CFC instances are intended to be singletons (i.e. you only need one instance of it in your application), then you definitely want to looking into Dependancy Injection. There are three main Dependancy Injection frameworks for CF; ColdSpring, WireBox and DI/1.
I'd suggest you look at DI/1 or WireBox as ColdSpring hasn't been updated for a while.
The wiki page for DI/1 is here:
https://github.com/framework-one/di1/wiki/Getting-Started-with-Inject-One
Wirebox wiki page is here:
http://wiki.coldbox.org/wiki/WireBox.cfm
Essentially what these frameworks do is to create (instantiate) your CFCs (beans) and then handles the dependancies they have on each other. So when you need to get your instantiated CFC it's already wired up and ready to go.
Dependancy Injection is also sometimes called IoC (inversion of control) and is a common design pattern used in many languages.
Hope that helps and good luck!
If your cfcs not related to each other the base.cfc concept does not fit. The inheritance is for classes have common things that can inherit from each other. For example if you have User.cfc and you want to added new cfc called customer.cfc I would inherit from User and override some functionality or add some without touching the actual user.cfc.
So, back to your question, since the CFC are not related or have common between each other and to avoid cross referencing, I will create serviceFactory holds instances of cfcs like this
component name="ServiceFactory"
{
function init(){
return this;
}
public User function getUserService(){
return new User();
}
public Calendar function getCalendar(){
return new Calendar();
}
}
and referencing it by
serviceFactory= new ServiceFactory();
userService = serviceFactory.getUserService();
Keep in mind this approach works only if you have sort of another CFC to manage your logic
you can do the same for all other services. If your functions are static you can save your services in application scope and instantiate it only one time (like singleton).
The third option you have is DI(dependency Injection) framework
Does Coldfusion have a "Global" structure where the expressions global["FORM"], global["URL"], global["APPLICATION"], global["SESSION"], etc. are valid?
no. Form, URL, Application, Session etc are all 'global' already. The underlying Java has got this, if you just want to dump out all the scopes at once:
<cfdump var="#getPageContext().getBuiltInScopes()#">
Or at least that used to work, but in CF9 you have to use this instead:
<cfdump var="#getPageContext().getCFScopes()#">
Sorry, but the answer is, "Nope." (am I up to 30 characters yet?)
My take is that you are out of luck with FORM and URL scope.
You can access all user sessions running on a CF instance using SessionTracker Java object:
<cfset sessionTrackerObj = createObject("java","coldfusion.runtime.SessionTracker")>
<cfoutput><p>There are #sessionTrackerObj.getSessionCount()# active sessions</p></cfoutput>
Dump the sessionTrackerObj to view its structure.
The same goes for the APPLICATION scope:
<cfset appTrackerObj = createObject(“java”,”coldfusion.runtime.ApplicationScopeTracker”)>
Enjoy!
Is there a way to make onrequestend.cfm call conditional.
i.e if I call a template through ajax, I don't want that onrequestend.cfm should be executed on ajax requests.
As in my case this is generating some header info like meta tags etc.
You have a few options:
Place a blank onRequestEnd.cfm in the directory containing the AJAX services you're connecting to, as Daniel recommends.
Switch to Application.cfc and the onRequestEnd() event instead of onRequestEnd.cfm; and inside your onRequestStart() event method, tell ColdFusion not to do anything for the onRequestEnd event.
Since you didn't specify, I'll guess and say that your AJAX requests use a CFC, like so:
/foo/bar.cfc?method=getSomething¶m=value
In which case, you can easily identify all requests being routed to a CFC like this:
function onRequestStart(targetPath){
if (listLast(arguments.targetPath, ".") eq "cfc"){
structDelete(this, "onRequestEnd");
}
}
Note that the function is only deleted for the current request, so you don't have to worry about it not being there for future requests. It will be.
There is not that I am aware of. However if you place all the templates you will be calling in a sub-directory and place a blank onRequestEnd.cfm in the sub-directory that should give you the same effect.
We handle this with URL variables. Call any page with
?NoHeaderFooter=true
and then conditional logic in onRequestStart like this:
<cfif NOT StructKeyExists(URL,"NoHeaderFooter")>
output header/footer etc. here
</cfif>
Can be used in both onRequestStart and onRequestEnd or create two variables so you can control each. Then all our ajax calls submit to something like:
report/FormController.cfc?Method=DoSomething&NoHeaderFooter=true
How can I pass a variable to a cfm page that I'm including from another page?
Example:
<cfset a.name = "me">
<cfset a.age = 135>
<cfinclude template="displayNameAndAgeFrom_A.cfm">
and displayNameAndAgeFrom_A.cfm is
<cfoutput>#a.name# #a.age#</cfoutput>
Thanks!
AFAIK, this should work, exactly the way you posted it, without having to pass anything at all. Any values available in the outside/calling page are available in the included page.
Also worth noting that you also have <cfmodule ... /> available. cfmodule will let you call the same template but you can pass in different values for the same attributes.
Check out ColdFusion 9 documentation on cfmodule.
This template/module however will only have access to a handful of scopes that the caller template has access to: request, session and application