How to create application variables in application.cfc - coldfusion

I'm new to using the application.cfc file in our application and some of these don't seem to be working and I can't figure out why. I have tried to cfdump "application". I get Application.DSN, Application.USERNAME, Application.Password, but not Application.SYSTEMPATH or Application.ACCOUNT
<cffunction name="onApplicationStart">
<cfscript>
Application.availableResources=0;
Application.DSN = "XXX";
Application.USERNAME = "XXX" ;
Application.PASSWORD = "XXX";
Application.SYSTEMPATH = "http://example.com/"; // This doesn't work
Application.ACCOUNT = XXX; // This doesn't work.
Application.counter1=1;
Application.sessions=0;
</cfscript>
</cffunction>

I think you want this:
Application.SYSTEMPATH = GetDirectoryFromPath(GetCurrentTemplatePath());
This will work too:
Application.SYSTEMPATH = expandPath( './' );
Now this...
Application.ACCOUNT = XXX; // This doesn't work. (because it is assuming XXX is a variable).
You need this:
XXX = 'something'; or XXX = 1; or Remove it altogether because it serves no purpose.
Then when you call:
Application.ACCOUNT = XXX; it won't give you errors.
Or you can just skip it and do this:
Application.ACCOUNT = 'something'; (a string)
Application.ACCOUNT = 1; (a number)
Then it won't fall apart (Because XXX is a variable not a value and you can't call a variable that doesn't exist).
So, if you have a 'variable' it has to have a 'value' (variable/value pair) or at least set a placeholder like XXX=0; or XXX=''; if you must have it.
Have I killed this variable/value dead horse to death??? Lol... :D
Jokes aside let us know if you have another question about your Application variables because some seem unnecessary (can't judge for sure though).

Related

Coldfusion Struct getting only numeric key list

I have a coldfusion Struct containing mix keys numeric and alpha, alphanumerics
I need to access only the numeric keys.
My code looks like
<cfset ids = structkeyList(st ) />
<cfset numericIDs = "" />
<cfloop list="#ids#" index="i">
<cfif IsNumeric(i)>
<cfset numericIDs = ListAppend( numericIDs , i ) />
</cfif>
</cfloop>
Is there a better method to solve such problems?
Is there a better method to solve such problems?
I would use something like this:
<cfset numericIDs = arrayToList(reMatch('\b\d+(?=,|$)\b', structKeyList(st)))>
Is there a better method to solve such problems?
I'd generally recommend working with arrays instead of lists.
In CF9 a loop similar to yours is as good as it gets. You can make a utility function out of it if you need it more than once. This one avoids StructKeyList() to be able to deal with all kinds of keys, independent of a separator character:
<cfscript>
function GetNumericKeys(struct) {
var keys = struct.keys();
var result = ArrayNew(1);
var key = "";
while (keys.hasNext()) {
key = keys.next();
if (IsNumeric(key)) ArrayAppend(result, key);
}
return result;
}
</cfscript>
and
<cfset nkeys = GetNumericKeys(st)>
In CF11 you can get a little more sophisticated (tested on CF11, can't say how CF10 handles this code).
<cfscript>
numericIDs = arrayFilter(structKeyArray(st), function (key) {
return IsNumeric(key);
});
</cfscript>
To ensure integer keys, use:
<cfscript>
numericIDs = arrayFilter(structKeyArray(st), function (key) {
return Int(key) eq key;
});
</cfscript>
I really don't see what's wrong with this. It should work quite well already, and it is very readable.
Sometimes working with a List is faster than an Array.
I had this:
<cfscript> function ListNumeric(principal) {
a=principal;
cleanlist = ''; for (i=1; i <= ListLen(a);i=i+1) { if(IsNumeric(ListGetAt(a,i))){ cleanlist = ListAppend(cleanlist,ListGetAt(a,i)); } } Return cleanlist; } </cfscript>
Also possible to work with regular expression:
inList2 = REReplace(inList,"[^0-9.]", "","ALL");

QueryAddRow throwing error in Coldfusion Webservice

I am facing a weird issue.
When I am consuming the below snippet of code as a webservice residing in a CF9 server I am getting the error "The value coldfusion.runtime.Struct cannot be converted to a number."
The call returns an array of structures. I would like to create a query from this array of structure. When I place this code as a standalone code in my local server(CF10) it works fine. But as soon i place it in the remote server to be invoked i get the error.
I almost pulled out my hair when I got the same error message even when I replaced the variable 'tempstruct' with a hard coded structure. As soon I remove the QueryAddRow I am able to return anything.
Any help is appreciated.
<cfset myquery=querynew("category,category_id,event_description","varchar,integer,varchar")>
<cfinvoke
webservice="http://199.99.99.999/vod_queries.cfc?wsdl"
method="getAllCategoryByResort"
returnvariable="arrAllSpaEvents"
refreshwsdl="true" >
<cfinvokeargument name="Resort" value="SRB" >
</cfinvoke>
<cfif arraylen(arrAllSpaEvents) GT 0>
<cfloop array="#arrAllSpaEvents#" index="cur_row">
<cfset tempstruct=StructNew()>
<cfset tempstruct.CATEGORY=cur_row.CATEGORY>
<cfset tempstruct.CATEGORY_ID=cur_row.CATEGORY_ID>
<cfset tempstruct.EVENT_DESCRIPTION=cur_row.EVENT_DESCRIPTION>
<cfset QueryAddRow(myquery,#tempstruct#)>
</cfloop>
</cfif>
<cfreturn myquery>
You almost got.
However, indeed you are using new CF10 overloading in CF9. What's more, if you were using CF10, it looks like you could stuff the whole top array in with looping like that.
But you can almost do the same thing. CF9 will take an array overload for the value.
Not quite as clean as CF10 but you do what you can.
Also, the extra # signs are superfluous.
Here is an example with something that your data might look like:
<cfscript> // I did this all in a cfscript block for simplicity
Your retrieved data might look something like this guessin from example
arrAllSpaEvents = [
{category='fun', category_id=1, event_description='massage'},
{category='work', category_id=2, event_description='spinning'},
{category='beauty', category_id=3, event_description='mani'},
{category='beauty', category_id=3, event_description='pedi'}
];
Create a more useful struct to build the query dynamically
s = {
category = {colType = 'varchar', colVals = []},
category_id = {colType = 'integer', colVals = []},
event_description = {colType = 'varchar', colVals = []}
};
This is looping the data to fill the colVals arrays
for(c = 1; c <= arrAllSpaEvents.size(); c++ ) {
for(k in arrAllSpaEvents[c]) {
s[k].colVals[c] = arrAllSpaEvents[c][k];
}
}
This is the short form of the same double loop above in a single line
for(c = 1; c <= arrAllSpaEvents.size(); c++ ) for(k in arrAllSpaEvents[c]) s[k].colVals[c] = arrAllSpaEvents[c][k];
Now build your query. Start with an empty query (pass in a blank);
q = queryNew('');
Then loop your struct and using the keys for the column names (for simplicity they are the same key)
for(k in s ) queryAddColumn(q,k,s[k].colType,s[k].colVals);
Verify your struct and query:
writedump(s);
writedump(q);
</cfscript>
I ran this in CF9 so should work fine for you.
This should get you going.

How do I retrieve the current value of enablecfoutputonly?

We are using Coldfusion 9.
Is there a simple way to know if enablecfoutputonly has been set to true during a particular request?
I cannot test with CF9 right now, but in CF10 it is accessible from getPageContext() by checking the output object:
<cfscript>
out = getPageContext().getOut();
// Is the cfsetting enablecfoutputonly value currently true?
isSettingEnabled = out.getDisableCount() > 0;
WriteOutput("isSettingEnabled="& isSettingEnabled &"<br>");
// Is output currently allowed?
isOuputtingEnabled = out.getDisableCount() == 0 || out.getOutputCount() > 0;
WriteOutput("isOuputtingEnabled="& isOuputtingEnabled &"<br>");
</cfscript>
.. or using reflection:
<cfscript>
out = getPageContext().getOut();
internalMethod = out.getClass().getDeclaredMethod("isOutputEnabled", []);
internalMethod.setAccessible( true );
isOuputtingEnabled = internalMethod.invoke( out, [] );
// is output currently allowed?
WriteOutput("isOuputtingEnabled="& isOuputtingEnabled);
</cfscript>

How to Deep Copy (clone) a structure while ignoring components

In versions of ColdFusion prior to 8 the duplicate function throws an error if there are any components in the structure. In 8 and beyond it will work, but there are issues when copying components.
So, What I need is a way to create a deep copy of a structure that ignores components. For my purposes it's for debugging, I need a snapshot of the variables scope at a particular point in the code, so efficiency doesn't really matter as this will never make it out of the development environment. Currently using CF 7, I would take what 8 offers if only to solve this immediate issue, but I don't control upgrade :(
While you were off killing brain cells, I took a stab at a recursive function ;) It excludes components and java/com objects. Neither of which MX7 can duplicate. I threw the functions into a component to avoid tampering with the variables scope. Then stored the instance in the request scope.
It is not rigorously tested. So I am sure there is room for improvement.
Usage
<cfset request.util = createObject("component", "Util")>
<cfset request.copy = request.util.duplicateStructMinusObjects(variables)>
<cfdump var="#request.copy#">
Util.cfc
<cfcomponent>
<cfscript>
function duplicateArrayMinusObjects(input) {
var x = "";
var value = "";
var output = arrayNew(1);
for (x = 1; x lte arrayLen(arguments.input); x = x + 1) {
value = arguments.input[x];
// note components are considered structures
if (IsStruct(value) and not IsObject(value)) {
arrayAppend(output, duplicateStructMinusObjects(value));
}
else if (IsArray(value)) {
arrayAppend(output, duplicateArrayMinusObjects(value));
}
else if (not IsObject(value)){
arrayAppend(output, duplicate(value));
}
}
return output;
}
function duplicateStructMinusObjects(input) {
var key = "";
var value = "";
var output = structNew();
for (key in arguments.input) {
value = arguments.input[key];
// note components are considered structures
if (IsStruct(value) and not IsObject(value)) {
output[key] = duplicateStructMinusObjects(value);
}
else if (IsArray(value)) {
output[key] = duplicateArrayMinusObjects(value);
}
else if (not IsObject(value)){
output[key] = duplicate(value);
}
}
return output;
}
</cfscript>
</cfcomponent>
Doesn't matter how long you think/search, you always come up with the answer right after you ask the question.
I was able to solve this by deliberately mis-using try/catch, so I looped through the structure, did a try on creating an object out of a each item as if it were a component, and on error, copied it to my snapshot structure. I also had to store it in a different scope, in my case I used session, since if I let it go to the default variables, there would be a circular reference that cause a structure with an infinite number of children.
EDIT: THIS DOES NOT DO WHAT I THOUGHT IT DID, SEE BELOW
<cfset session.varSnapShot = StructNew()>
<cfset loopList = StructKeyList(variables)>
<cfloop from="1" to="#ListLen(loopList)#" index="i">
<cftry>
<cfobject name="x#i#" component="#variables[ListGetAt(loopList,i)]#">
<cfcatch>
<cfset session.varSnapShot[ListGetAt(loopList,i)]= variables[ListGetAt(loopList,i)]>
</cfcatch>
</cftry>
</cfloop>
EDIT: Since the above doesn't actually do a deep copy (thanks Leigh) I came up with this:
<cfloop from="1" to="#ListLen(loopList)#" index="i">
<cfset metaData = GetMetaData(variables[ListGetAt(loopList,i)])>
<cfif isStruct(metaData) AND isDefined("metaData.type") AND metaData.type EQ "component">
<cfelse>
<cfset session.varSnapShot[ListGetAt(loopList,i)]= duplicate(variables[ListGetAt(loopList,i)])>
</cfif>
</cfloop>
This does make a deep copy but will still be a problem if a component is below the first level of an object. I wanted to create a recursive method, but It's an hour and a half past quitting time on a Friday. I will instead kill brain cells at the pub and maybe update this with the recursive method on Monday if I don't forget.
a modern update to this question:
why not just use #serializeJSON(deserializeJson(theObject))#
that way you get deep copy with no components.

Subsonic 3 Save() then Update()?

I need to get the primary key for a row and then insert it into one of the other columns in a string.
So I've tried to do it something like this:
newsObj = new news();
newsObj.name = "test"
newsObj.Save();
newsObj.url = String.Format("blah.aspx?p={0}",newsObj.col_id);
newsObj.Save();
But it doesn't treat it as the same data object so newsObj.col_id always comes back as a zero. Is there another way of doing this? I tried this on another page and to get it to work I had to set newsObj.SetIsLoaded(true);
This is the actual block of code:
page p;
if (pageId > 0)
p = new page(ps => ps.page_id == pageId);
else
p = new page();
if (publish)
p.page_published = 1;
if (User.IsInRole("administrator"))
p.page_approved = 1;
p.page_section = staticParent.page_section;
p.page_name = PageName.Text;
p.page_parent = parentPageId;
p.page_last_modified_date = DateTime.Now;
p.page_last_modified_by = (Guid)Membership.GetUser().ProviderUserKey;
p.Add();
string urlString = String.Empty;
if (parentPageId > 0)
{
urlString = Regex.Replace(staticParent.page_url, "(.aspx).*$", "$1"); // We just want the static page URL (blah.aspx)
p.page_url = String.Format("{0}?p={1}", urlString, p.page_id);
}
p.Save();
If I hover the p.Save(); I can see the correct values in the object but the DB is never updated and there is no exception.
Thanks!
I faced the same problem with that :
po oPo = new po();
oPo.name ="test";
oPo.save(); //till now it works.
oPo.name = "test2";
oPo.save(); //not really working, it's not saving the data since isLoaded is set to false
and the columns are not considered dirty.
it's a bug in the ActiveRecord.tt for version 3.0.0.3.
In the method public void Add(IDataProvider provider)
immediately after SetIsNew(false);
there should be : SetIsLoaded(true);
the reason why the save is not working the second time is because the object can't get dirty if it is not loaded. By adding the SetIsLoaded(true) in the ActiveRecord.tt, when you are going to do run custom tool, it's gonna regenerate the .cs perfectly.