Coldfusion dynamic variable naming - coldfusion

It's possible with coldfusion convert this php code?
if ( $_GET[ 'bSortable_'.intval($_GET['iSortCol_'.$i]) ] == "true" ){
//do something...
}
I have tried something as:
if( structKeyExists( url , "bSortable_[iSortCol_[#i#]]" ) ) {
}
But seems not working....probably I should try another way to make this?
The variables are two:
bSortable_1 = true;
iSortCol_1 = 1;
I should obtain bSortable_1 value....

I am not much familiar with PHP but it seems that you are passing bSortable_1, iSortCol_1 kind of query variable to make sorting of table. I guess below code should work foe you.
<cfset url.bSortable_1 = 1>
<cfset url.iSortCol_1 = 1>
<!--- Option 1 --->
<cfif structKeyExists(URL,"bSortable_#URL.iSortCol_1#")>
<cfoutput>Exists</cfoutput>
</cfif>
<!--- Option 2 --->
<cfset i = 1>
<cfif URL['bSortable_#URL['iSortCol_#i#']#']>
<cfoutput>Exists</cfoutput>
</cfif>
Although I found this is so complex. I will suggest go for some nicer option.

This is explanation requested in the comments. There are at least two url variables available, bSortable_1 and iSortCol_1. Both the php code and Pritesh's answer have this sort of structure.
<cfif somethingabout_bSortable_1.somethingabout_iSortCol_1>
do something
By treating the variables separately, my structure would resemble this:
<cfif somethingabout_bSortable_1 and (or or) somethingabout_iSortCol_1>
do something
Going to the StructkeyExists function, but with static values, it would be this
<cfif StructKeyExists(url, "bSortable_1") and StructKeyExists(url, "iSortCol_1")>
do something
For dynamic values, I don't know what would work so I would have to find out. Having said that, the first thing I'd try is:
<cfloop from = "1" to = SomeMaximum index = "i">
<cfif StructKeyExists(url, "bSortable_#i#") and StructKeyExists(url, "iSortCol_#i#")>
do something
closing tags

Related

Parse the contents of a Coldfusion variable into separate variables

OK, so I've been banging my head against this one for a while and getting nowhere. I've been attempting to take the contents of a variable and parse the contained string into parts that would then be ingested into 5 separate variables. Seems simple enough right? Well, it has not proven to be simple at all, at least for me.
So I have a variable (PageContent) that contains the trimmed content from a CFHTTP request.
The PageContent variable now contains:
<tdnowrapalign=right>07/18/2020 13:00</td>
<tdalign=right>1002.12</td>
<tdalign=right>2,874,887</td>
<tdalign=right>12,766</td>
<tdalign=right>13,038</td>
It seems like there should be an easy way to write a loop that would loop over the tags in the "PageContent" variable assigning the content of each tag to a different variable. But every way I try to parse the data in the variable I either get an error (Complex object types cannot be converted to simple values.) or I end up with the content that I originally had in the "PageContent" variable repeated within the loop.
For instance, if I had a loop that would run through 5 iterations and could grab the contents of the tags assigning each to a variable then the desired result would be:
DateTime = "07/18/2020 13:00"
Elevation = "1002.12"
Storage = "2,874,887"
Outflow = "12,766"
Inflow = "13,038"
After trying every example I could find here and elsewhere online I'm now on something like my 100th attempt. Now I'm trying to use regular expressions to grab the contents of the tags and assign them to variables but no luck there. What I ended up with was the entire contents of the PageContent variable being stuffed into each one of the variables. The result was not really unexpected since I don't know of a way to differentiate between the 3 identical "tdalign" tags, but still it seems like at least the first variable would have worked since the tag was different "tdnowrapalign".
<cfset i=5/>
<cfloop index = "LoopCount" from = "1" to = #i#>
<cfif i EQ 1>
<cfset dataDateTime = Replace(PageContent, "<[tdnowrapalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 2>
<cfset elevation = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 3>
<cfset storage = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 4>
<cfset outflow = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
<cfelseif i EQ 5>
<cfset inflow = Replace(PageContent, "<[tdalign][^>]*>(.+?)</[td]>","","ALL")>
</cfif>
<cfoutput>
<cfif isdefined("dataDateTime")>
dataDateTime = #dataDateTime#<br>
</cfif>
<cfif isdefined("elevation")>
elevation = #elevation#<br>
</cfif>
<cfif isdefined("storage")>
storage = #storage#<br>
</cfif>
<cfif isdefined("outflow")>
outflow = #outflow#<br>
</cfif>
<cfif isdefined("inflow")>
inflow = #inflow#<br>
</cfif>
</cfoutput>
<cfset i = i - 1>
</cfloop>
Does anyone know if there is a way to get to the desired outcome I described where I end up with 5 variables containing the contents of the tags contained within the "PageContent" variable?
One way of doing it would be like this
<cfset PageContent = '<tdnowrapalign=right>07/18/2020 13:00</td>
<tdalign=right>1002.12</td>
<tdalign=right>2,874,887</td>
<tdalign=right>12,766</td>
<tdalign=right>13,038</td>' />
<cfset data = ListToArray(PageContent, '</td>', false, true) />
<cfset DateTime = ListLast(data[1], '>') />
<cfset Elevation = ListLast(data[2], '>') />
<cfset Storage = ListLast(data[3], '>') />
<cfset Outflow = ListLast(data[4], '>') />
<cfset Inflow = ListLast(data[5], '>') />
Demo: https://trycf.com/gist/b4f3b630bd1cbdc505d07a7d79b68ef5/acf?theme=monokai

CF9: What is this evaluate statement evaluating?

I'm stuck and need a fresh set of eyes on this, please.
I'm working with someone else's spaghetti code who is no longer around and having a heck of a time figuring out what they were evaluating.
<cfset surveyCount = 0>
<cfloop query="surveys">
<cfif evaluate("defaultReport" & ID)>
<cfset surveyCount = surveyCount + 1>
</cfif>
</cfloop>
In the query dump, I see 9 records which is what I am expecting but because because the evaluate is failing, the surveyCount isn't being incremented. I do not see any columns for defaultReport. In my 15 years of working with CF, I've always avoided evaluate() and now when I need to analyze it, I'm at a complete loss. Can someone offer any guidance?
Added CFDump image (some columns names have been removed for privacy and security):
UPDATE I:
This file has numerous cfinclude statements and very little code formatting. As a result, I overlooked some cfinclude statements. I found the following. I'm still looking but wanted to document this as I dig.
<cfloop query="surveys">
<cfscript>
variables["defaultReport" & ID] = evaluate(thisAssociation & "Price");
</cfscript>
</cfloop>
UPDATE II:
Dumping the variable scope, I did confirm the variable I am looking for (finding the query I posted in UPDATE I helped, too). :)
What they wanted to do is to increase surveyCount but only if this thing: evaluate("defaultReport" & ID) evaluates to true.
From your query dump picture it looks like the IDs are numbers like 144, 145, etc...
In this context, you can think at evaluate("defaultReport" & ID) as something like defaultReport144, defaultReport145, etc... (these are variables set somewhere in the code).
So the code:
<cfif evaluate("defaultReport" & ID)>
<cfset surveyCount = surveyCount + 1>
</cfif>
becomes (for an ID of 144, the first one on your query loop)
<cfif defaultReport144>
<cfset surveyCount = surveyCount + 1>
</cfif>
and so on... for the other IDs
So, search your code for where variables like defaultReport144, defaultReport145, etc... are set to either true or false (0 or 1).
Something like:
<cfset defaultReport144 = true />
or maybe they use some expression that evaluates to true or false, like:
<cfset defaultReport144 = [some expression] />
If you can't find, then maybe the code was changed or removed in the place where these defaultReport... variables were set.
ColdFusion evaluate() documentation:
https://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7f4e.html
You need to look for a variable outside of your query. This variable has a name of default#ID# . It may be called.
variables.default#ID#
form.default#ID#
url.default#ID#
request.default#ID#
attributes.default#ID#
etc.
Basically ColdFusion is going to go through every scope until it finds something. (No this is not a good approach)
If you have to clean this up, I would recommend not using such an ambiguous approach. In short, there is no real way to know what it is evaluating.

Access a coldfusion variable without knowing the name

Is there a syntax in coldfusion that will let me do that following?
<cfif DataSet2.RecordCount gt 0 >
<cfset append = #ArrayAppend(DataSet2Results,VAL(DataSet2.RecordCount))# >
</cfif>
Replacing the '2' in each case with an variable name (an index in a loop in this case).
So it would look like:
<cfif DataSet#index#.RecordCount gt 0 >
<cfset append = #ArrayAppend(DataSet#index#Results,VAL(DataSet#index#.RecordCount))# >
</cfif>
I know I can do a two dimensional array for this, but it would save me a slice of time if this can be done.
I found the answer to my own question. I used Variables["DataSet#index#"].recordcount and so on.

Having some trouble understanding loops

I created this for some reason neither one of the queries are being updated
<cfloop index="i" from="1" to="#ArrayLen(location)#">
<cfif location[i] NEQ "" AND #locationID# EQ "" >
<cfquery Name="UpdateAddActivity" DATASOURCE="#DS#">
INSERT INTO tblProjectLocations
(
projectID,
locationID
)
VALUES
(
#ProjectName#,
#location[i]#
)
</cfquery>
</cfif>
<cfif location[i] EQ "" AND #locationID# NEQ "" >
<cfquery Name="UpdateAddActivity" DATASOURCE="#DS#">
DELETE FROM tblProjectLocations
WHERE locationID = #locationID# AND projectID = #ProjectName#
</cfquery>
</cfif>
</cfloop>
Am I looping correctly? It doesn't seem like to me that the accumulator is ever going to be updated but loops are done this way every place that I've looked.
Your cfloop tag is fine - you only need index/from/to attributes for a basic loop.
The index variable is incremented (and the loop re-processed) at the position of the closing tag. Or to put it another way, the body code is executed once for each index value between from and to (inclusive).
For information, you can change the default increment (of 1) by specifying the step attribute (though that obviously doesn't make sense for an array loop).
When your code isn't performing as expected, you can debug it with the dump tag:
<cfloop ... >
...
<cfdump var=#locationID# abort />
...
</cfloop>
The abort attribute will stop processing - the loop will not iterate and the current page content will be returned (it's shorthand for specifying cfabort tag separately.
You can use multiple dumps, and the label attribute to help identify which is which, but obviously if using abort attribute make sure only the last one has it.
As has been mentioned locationID isn't defined in the snippet you've provided, so may be the issue.
Sometimes spaces can cause issues - you may want to use the trim function to ensure you're dealing with empty strings (though blindly wrapping trim functions everywhere is ugly - always try if possible avoid introducing spaces).
Shortcut Array Looping
The from/to loop you've got there is only one type of cfloop - there are others.
Specifically, when you don't need the numeric index, there is a shorthand array loop:
<cfloop index="CurLocation" array=#Location# >
...
</cfloop>
Which is equivalent to:
<cfloop index="i" from=1 to=#ArrayLen(Location)# >
<cfset CurLocation = Location[i] />
...
</cfloop>
But without the unused i variable. (If you need the i variable, stick to from/to.)
Note that inside a function you should almost always write index="local.i" and index="local.CurLocation" to ensure the variables are appropriately scoped. This isn't unique to loops - it applies to any tags that create variables. You can also do <cfset var i = 0 /> prior to the loop to do the same thing.
Unrelated Issues
There are a couple of other issues with your code.
Most importantly, the code you're showing is potentially at risk of SQL injection. You should almost never write SQL with bare hashes in, and instead parameterise your queries - using cfqueryparam tag - to solve this. (In the situations where you can't use parameters (e.g. within ORDER BY) make sure you have appropriately sanitized any dynamic text.
Less important -- it doesn't change how the code works, but does betray a lack of experience and understanding -- are the superfluous hashes around locationID. A simplified explanation is that you generally only need #s inside strings (i.e. where the contents would otherwise be treated as text, rather than being a variable's value.)
When in doubt, look at your data.
<cfoutput>
<cfloop index="i" from="1" to="#ArrayLen(location)#">
i is #i# <br>
<cfif location[i] NEQ "" AND locationID EQ "" >
true location is #location[i]# <br>
<cfelse>
false location [i] is is #location[i]# and
locationid is #locationID# <br>
</cfif>
<cfif location[i] EQ "" AND locationID NEQ "" >
same as above
</cfif>
</cfloop>
</cfoutput>
Then you'll know why you are not getting the results you expect.
As long as there are items in your location array, the loop will run and the CFLoop tag will take care of incrementing i.
What I'd guess is happening is that you are checking two conditions within the loop and if neither match, no code will run. You're handling these:
location[i] NEQ "" AND #locationID# EQ ""
location[i] EQ "" AND #locationID# NEQ ""
but not these:
location[i] EQ "" AND #locationID# EQ ""
location[i] NEQ "" AND #locationID# NEQ ""
Could that be it?

advanced cfif statement

How would I create this statement in CF?
<cfif (not isdefined("URL.room") or #URL.room# EQ "")
and (not isdefined("URL.system" or #URL.system# EQ "")
and (not isdefined("URL.date") or #URL.date# EQ "")>
Obviously the parentheses don't work, but illustrate what I am trying to accomplish. What is the syntax for this?
EDIT:
Ok, I understand how to use EQ and all that. I posted this in a bit of a hurry. My question is about the parentheses. Is it syntactically correct to use them this way?
EDIT: Ok, I understand how to use EQ
and all that. I posted this in a bit
of a hurry. My question is about the
parentheses. Is it syntactically
correct to use them this way?
Syntactically, yes. The code's syntax is correct and will not throw syntax errors.
However, it's not necessarily the best way to do it. At the very least you should have linebreaks in there, to make it more readable, like so:
<cfif (not isdefined("URL.room") or URL.room EQ "")
and (not isdefined("URL.system" or URL.system EQ "")
and (not isdefined("URL.date") or URL.date EQ "")
>
And I would be more inclined to write it like this:
<cfif NOT
( ( isDefined('Url.Room') AND Len(Url.Room) )
OR ( isDefined('Url.System') AND Len(Url.System) )
OR ( isDefined('Url.Date') AND Len(Url.Date) )
)>
Because that's much more readable, and makes it more obvious that each row is checking the same thing.
That is assuming I was doing this in a single IF statement, anyway.
If you start getting lots of conditions to check, you might want to consider doing something like this instead:
<cfset FieldList = "Room,System,Date" />
<cfset AllFieldsValid = true />
<cfloop index="Field" list="#FieldList#">
<cfif NOT ( StructKeyExists(Url,Field) AND Len(Url[Field]) )>
<cfset AllFieldsValid = false />
<cfbreak/>
</cfif>
</cfloop>
<cfif AllFieldsValid>
...
Which might look intimidating at first, but is much easier to maintain - you just add a new item to FieldList (and you may already have a variable which serves that purporse).
Anyway, hopefully all this helps - let me know if any questions on it.
I'd prefer...
<cfparam name="URL.room" default="">
<cfparam name="URL.system" default="">
<cfparam name="URL.date" default="">
<cfif len(URL.room) EQ 0 and len(URL.system) EQ 0 and len(URL.date) EQ 0>
...
</cfif>
Or if you're comfortable with mixing non-boolean functions and boolean expression
<cfif len(URL.room) and len(URL.system) and len(URL.date)>
...
</cfif>
replace the = with eq
In CFML the comparison operators use characters rather than symbols:
== EQ
!= NEQ
> GT
>= GTE
< LT
<= LTE
Similarly with boolean operators:
! NOT
&& AND
|| OR
You can still use the traditional symbols in CFScript mode.
Also worth mentioning that Railo, an alternative CFML engine to Adobe ColdFusion, allows you to use the symbols in tag-based code, if there is no ambiguity with closing tag (e.g. the condition is wrapped in parentheses).
#Henry:
<cfif len(URL.room) EQ 0 and len(URL.system) EQ 0 and len(URL.date) EQ 0>
...
</cfif>
Shorter:
<CFIF Len(URL.room) AND Len(URL.system) and Len(URL.date)>
Len() is better than EQ ""
You need to think your logic through a bit.
You can't check to see if room is an empty string if it is undefined.
Probably what you really need is :
If (structkeyexist(URL,"room") and (Len(URL.room) eq 0 or URL.room eq 'blah'))
Do something
Else
Do something else
I'm afraid stackoverflow cuts off your example condition on my phone, but hopefully this illustrates what you need to do.