I'm using Lucee CFML to create a website.
I have a global variable stored in application.cfc like this:
component {
application.globalquery;
}
On the second page of the website, I assign a value to that variable:
<cfscript>
myquery = ["object1", "object2", "object3", "object4", "object5"];
application.globalquery = myquery;
</cfscript>
On a third page, I dump the globalquery variable:
<cfscript>
dump(var="#application.globalquery#");
</cfscript>
But the result of this dump is string: empty
The expected behavior should be, that it contains the 5 objects of myquery.
Why isn't that the case?
You're resetting the value on every request.
By putting the definition at the root of the component:
component {
application.globalquery;
}
You're essentially telling CF to run that code on every request, like this:
component {
function onRequestStart() {
application.globalquery;
}
}
You need to define that variable only once, when the application starts, like this:
component {
function onApplicationStart() {
application.globalquery;
}
}
From then on, the value should only change when you tell it to change.
Here's more info on Application.cfc. There may be a few differences between Adobe CF and Lucee.
Related
I have a cfc that is a service. It only has functions. Up until now did not have any member variables.
login.cfc
function post(required string email, required string password) {
...
variables.password = arguments.password; // wish I didn't have to do this
var User = entityLoad("Users", {email : arguments.email}).filter(
function(item){
return item.validatePassword(variables.password);
});
variables.password = "";
...
I don't like that I have to set arguments.password to variables.password just so that the function inside of .filter can see it. Isn't there a cleaner way to do this?
In CF11 and newer, including Lucee 4/5, CFML closures can access variables in the parent scope (and up the stack). CF10 seems to have problems with this... but here's the code you can run in https://trycf.com to see how it works on each version of ColdFusion:
<cfscript>
function doFilter(term) {
var superheroes=[
{"name":"Iron Man","member":"Avengers"},
{"name":"Wonder Woman","member":"Justice League"},
{"name":"Hulk","member":"Avengers"},
{"name":"Thor","member":"Avengers"},
{"name":"Aquaman","member":"Justice League"}
];
var filtered=superheroes.filter(function(item){
return item.member==term;
});
writeDump(filtered);
}
doFilter("Avengers");
</cfscript>
So, in other words, you should have access to the arguments in the post() method if you're using CF11 or newer, or Lucee.
I have a remote function in a component that's being affected by my Application.cfc - onRequestStart is requiring the user to login. I don't want to move the .cfc into another subfolder - I want to keep it as close to the .cfm as possible so that I don't have to go hunting for the cfc while editing the .cfm.
I think the solution is to use onRequest and onCFCRequest instead of onRequestStart, but in experimenting with onCFCRequest, it looks like the return value has to be boolean. So now my remote function is returning a boolean instead of the query that it used to.
Rays' example shows outputting the result, but what about returning the result?
Here's what I tried, but ColdFusion balked at the return value not being boolean:
public boolean function onCFCRequest(string cfc, string method, struct args) {
local.comp = createObject("component", arguments.cfc);
local.result = evaluate("local.comp.#arguments.method#(argumentCollection=arguments.args)");
return local.result;
}
Your problem is this assertion:
in experimenting with onCFCRequest, it looks like the return value has
to be boolean
That's not true.
It can (and should) be "any", in which case it'll return whatever data type the called method returns (serialised so it can be transmitted in the HTTP response, natch).
I am using a proxy/delegate pattern in a coldfusion component, and am getting unexpected results (from my point of view). Below is my proxy component - its pretty straight forward, I just init the CFC with the actual component I want to delegate to, and then map the named functions from that CFC through to a proxy function (the below is simplified for this example)
I have created a proxy component as follows:
component output="false"{
/** Constructor for proxy - requires an instance of myFusebox **/
public MyFuseboxProxy function init( Required any myFb ){
variables.myFusebox = arguments.myFb;
return this;
}
this.do = variables.proxy;
this.getApplication = variables.proxy;
this.getApplicationData = variables.proxy;
private any function proxy(){
var local.functionName = getFunctionCalledName();
var local.function = variables.myFusebox[local.functionName];
var local.returnVal = local.function( argumentCollection=arguments );
return local.returnVal;
}
}
From my application I call the following code:
variables.myFusebox = new ab.MyFuseboxProxy( variables.myFusebox );
variables.myFusebox.getApplicationData().startTime = now();
Now, in the above scenario, I would expect my proxy component to map the getApplicationData() function straight through to the original myFusebox component (via my proxy() function).
That function in the underlying component is as follows:
<cffunction name="getApplicationData" returntype="struct" access="public" output="false"
hint="I am a convenience method to return a reference to the application data cache.">
<cfreturn getApplication().getApplicationData() />
</cffunction>
That proxy all works fine, however, once I am in the above function in the original myFusebox I get the following error:
Message: Variable GETAPPLICATION is undefined.
StackTrace: coldfusion.runtime.UndefinedVariableException: Variable GETAPPLICATION is undefined.
And if I dump "this" inside that function, it actually dumps my proxy object.
Can anyone explain this or what I have done wrong? I was expecting that once the function call was inside the underlying object, it would just use its own context from there (my proxy just being a pass through really to the delegate)
I think this is the key point:
I was expecting that once the function call was inside the underlying
object
You've got this:
private any function proxy(){
var local.functionName = getFunctionCalledName();
var local.function = variables.myFusebox[local.functionName];
var local.returnVal = local.function( argumentCollection=arguments );
return local.returnVal;
}
When you do this bit:
var local.function = variables.myFusebox[local.functionName];
you are effectively pulling the function referenced by local.functionName out of variables.myFusebox, and putting it into the current function, within the context of your MyFuseboxProxy instance.
So when you do this:
var local.returnVal = local.function( argumentCollection=arguments );
You are not running variables.myFusebox[local.functionName]() (so in the context of variables.myFusebox), but you are running local.function() (so in the context of your proxy object).
I don't have the patience to try to follow your logic here, but I am still surprised you get that error. I would have expected this to happen:
local.function (a reference to getApplicationData from variables.myFusebox) runs getApplication().
getApplication() in the context of the MyFuseboxProxy instance should be a reference to variables.proxy().
variables.proxy() resolves the proxied function as getApplication(), and pulls that out of variables.myFusebox, and runs it in the context of your MyFuseboxProxy instance.
You do not include the code of the getApplication() function from variables.myFusebox, so I dunno what would happen next, but this is not what you want to be happening.
Anyway, the crux is - I think - that instead of running the functions inside variables.myFusebox, you're running them in your MyFuseboxProxy instance instead. If you want to do this sort of proxying (and ignoring for a moment you have invoke() specifically for doing this), you need to still call the function in its original context, not reference it in some new context.
I guess you're doing all this horsing around because ColdFusion doesn't like this syntax:
someObject[someMethodName]()
It baulks at the []() notation. However the solution is not this:
someOutOfContextReference = someObject[someMethodName]
result = someOutOfContextReference()
It's this:
someObject.someInContextReference = someObject[someMethodName]
result = someObject.someInContextReference()
See the subtle difference?
ColdFusion functions are not intrinsically closures, which is what you'd need them to be to work the way you want.
I've inherited a project where there are a number of remote CFC's opened up for some Ajax requests and inside most methods in the CFC have the following:
<cfset var this.response = true />
Now I've never seen the var and this scope used together like this so I'm really not sure what to make of it so I guess my questions is:
Are there any issues with how this was coded? If so, are they major enough that I should put in
the effort to update all the CFC's to something like <cfset var
req.response = true />?
Here is a quick example of what I'm seeing:
<cfcomponent>
<cffunction name="check_foo" access="remote" returnformat="plain">
<cfargument
name = "isfoo"
type = "string"
required = "false"
default = "nope"
hint = "I check the string for foo"
/>
<cfscript>
/*setup new response*/
var this.response = false;
/*check for foo*/
if( !findnocase( "foo", arguments.isfoo ) ) {
/*no foo!*/
this.response = false;
}
return this.response;
</cfscript>
</cffunction>
</cfcomponent>
.
Updates:
Based on the feedback/answers below I've replace all instances of var this. Thanks again to everyone that helped out!
.
update: upon checking your dump, the "this" in var this is still this this scope, not local.this.
It is setting the response to the this scope, and it works in this case because because the CFC is instantiated every time it's being invoked remotely. However, it'd be best to rename this into something else to ensure thread-safety in case the method is invoked by other CFC as public method.
Using var this is the same as using this.
Dumping the local scope will include local variables as well as the Arguments and This scopes. (Can't find this documented; but I get this result in a bare cfc, and you got it in your screenshots.)
Because your function is access="remote" you'll be getting a new instance of the cfc on every call, and therefore a bare This scope. So those are "safe", but still a bad idea.
If there is any use of var this in non-remote functions then you will be getting undesired persistence and may suffer race conditions that result is invalid data.
Relevant CF documentation:
"Methods that are executed remotely through Flash Remoting and web services always create a new instance of the CFC before executing the method."
"Variable values in the This scope last as long as the CFC instance exists and, therefore, can persist between calls to methods of a CFC instance."
I am using ColdFusion 8.0.1.
I am writing a little code in the application file that will look at the URL. If any of a certain type of property is passed, I don't want to update a property in a SESSION structure.
Basically, if a visitor accesses any page that has to do with our registration process, we do not want to update the SESSION.UserInfo.ReturnToURL variable. For every other page they access, we want to update the variable.
All pages that have to do with the registration process will have "myiq.reg" in the URL. If this were the case, I would use the code below.
// DETERMINE WHETHER TO UPDATE RETURNTOURL
if (not structKeyExists(URL, "myiq.reg")) {
URLString = "http://" & CGI.SERVER_NAME & CGI.SCRIPT_NAME & CGI.QUERY_STRING;
SESSION.UserInfo.ReturnToURL = URLString;
}
But it's not that simple. My people want to be able to pass other properties that are similar, like this:
myiq.reg_confirm
myiq.reg_password
myiq.reg_save
I need to be able to soft code these to work with any registration page that they might create in the future. Basically, I need something like this :
if (not structKeyExists(URL, "myiq.reg*")) {
SESSION.UserInfo.ReturnToURL = URLString;
}
Notice the WILDCARD after "myiq.reg". I've tried this, but it doesn't work.
How do I code this so that any page that is access with a URL property that begins with "myiq.reg" is ignored?
You could get a structKeyList() of the URL scope, and just do a regex find in that. Something like:
reFindNoCase("(?:^|,)myiq\.reg", structKeyList(URL))
(only superficially tested)
You could improve the regex a bit if you wanted to more accurately match actual variable name patterns rather than just any occurrence of myiq.reg in the string.
Something like this perhaps...
res = '';
params = StructKeyList(url);
for(i=1; i lte ListLen(params); i++) {
param = listGetAt(params, i);
if (CompareNoCase(Left(param, 8), 'myiq.reg') eq 0) {
res = param;
break;
}
}