ArrayAppend returning boolean instead of array - data-structures

OK I have been struggling with this for sometime and I figured I would go back to the basics and try and figure out my error, as I get the same error here as I do down the line.
Here is my Code:
<cfparam name="session.cart" default="arrayNew(1)">
<cfset session.cart = arrayAppend(session.cart,structNew() )>
<cfset thisCartItem = arraylen(session.cart)>
<cfset session.cart[thisCartItem].itemID = "X">
<cfset session.cart[thisCartItem].quantity = "X">
<cfset session.cart[thisCartItem].itemName = "X">
<cfdump var="#session.cart#">
Here is my error:
Object of type class java.lang.Boolean cannot be used as an array

The error means exactly what it says. The variable session.cart is not an array. It is a boolean value. If you read the ArrayAppend documentation it explains why. The function modifies the array in place and returns a boolean value:
Returns True, on successful completion.
By capturing the result here, you are actually setting the cart value to true/false:
<!--- Note the addition of the pound signs in the CFPARAM --->
<cfparam name="session.cart" default="#arrayNew(1)#">
<cfset session.cart = arrayAppend(session.cart, structNew())>
Having said that, you could simplify the code a lot by using the shorthand syntax supported in all recent versions of CF ie {} - new structure and [] - new array. To create a new array:
<cfset session.cart = []>
To append one or more structures to the end of that array:
<!--- append first structure to array --->
<cfset ArrayAppend( session.cart
, { itemID = "X", quantity = "X", itemName = "X" }
)>
<!--- append second structure to array --->
<cfset ArrayAppend( session.cart
, { itemID = "Y", quantity = "Y", itemName = "Y" }
)>

Related

I have a need to see all session scope for all logged in users in ColdFusion2018

I start with this find;
<cfscript>
app = application.getApplicationSettings().name;
sessionCollection = application.sessionTracker.getSessionCollection(app);
</cfscript>
and then attempt to loop thru the collection;
<cfloop collection="#sessionCollection#" item="i">
#StructFind(i, 'CurrentAction')#
</cfloop>
which fails with;
You have attempted to dereference a scalar variable of type class java.lang.String as a structure with members.
I have tried
#CurrentAction[i]#
which fails with;
Variable CURRENTACTION is undefined.
when I know for a fact it exists
(https://ibb.co/ZJwsKFS)
Ive tried dot notation as well.
The purpose is to identify an ajax listener activity for one user, and affect an action on another specific user as a response. I am under the impression I can send an action by sessionID end user. Please feel free to let me know if this is NOT possible.
So this code:
<cfset x = {
a = 1
, b = 2
, c = 3
}>
<cfoutput>
<cfloop collection="#x#" item="i">
<li>#i#</li>
</cfloop>
</cfoutput>
Outputs the following:
A
B
C
Which means that i is the key of the struct defined in the collection attribute. Your code is trying to find a key in the collection (struct), but you're referencing the wrong variable.
To find the value of B, you would do StructFind(x, "b"). You don't need the cfloop either, you just need to check if the key exists, then get the value.
<cfset someVariable = "">
<cfif structKeyExists(x, "b")>
<cfset someVariable = structFind(x, "b")>
</cfif>

XPath cannot detect class name when contains return char

I have a problem with XPath selector. When the class name has return char(or may be for another reason!) it cannot select the node by class name. Anyone can help me?
var html =
#"<INPUT class=box value=John maxLength=16 size=16 name=user_name>
<INPUT class='
box1' value=Tony maxLength=16 size=16 name=user_name>
";
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(html);
var htmlNodes =
htmlDoc.DocumentNode.SelectNodes("//input[#class='box1']");
Console.WriteLine(htmlNodes == null);
htmlNodes = htmlDoc.DocumentNode.SelectNodes("//input[#class='box']");
Console.WriteLine(htmlNodes == null);
In the first input tag classname is in the same line with class but in the second input element class name is the below line.
The result of first console is True and for the second is False
https://dotnetfiddle.net/HGP9H3
The problem is that the #class value of box1 contains a line break and some spaces. So the check of the predicate in the expression
//input[#class='box1']
fails and you get a true for the null check.
You have two possibilities to fix that:
Remove all spaces/line breaks with normalize-space in the predicate like this:
//input[normalize-space(#class)='box1']
Remove the line break from the HTML snippet like this:
var html =
#"<INPUT class=box value=John maxLength=16 size=16 name=user_name>
<INPUT class='box1' value=Tony maxLength=16 size=16 name=user_name>
";

Check if argument exist in ColdFusion

I have a question about arguments that are passed with ajax in coldfusion. So I have three arguments that I'm passing date1, date2 and meetingDate. I have to compare three of these arguments and return the string based on the dates. Here is my logic:
<cfset sigDate1 = dateFormat(trim(arguments.date1),'yyyy/mm/dd')>
<cfset sigDate2 = dateFormat(trim(arguments.date2),'yyyy/mm/dd')>
<cfset meetDate = dateFormat(URLDecode(arguments.meetingDate),'yyyy/mm/dd')>
<cfelseif (sigDate1 LT meetDate) OR (sigDate2 LT meetDate)>
<cfset myResult = "blockDate">
<cfelse>
My current code has one problem, if I just pass one of these two dates(date1 or date2) I will always get "blockDate" returned with my ajax function. I detected the problem and if I just pass date1 but not date2 my elseif still will be executed no matter what. So I was trying to fix this problem with using one extra cfif and check if my date1 and date2 isDefined but that did not fix the problem. If anyone have any idea how to fix this bugg please let me know.
Thanks in advance.
There are a couple different ways to handle this. As I understand it; the arguments always exist, but you are concerned they may have blank values.
Here are some ideas you should be able to adapt to get you started:
use defaults
<cfset sigDate1 = iif(isDate(trim(arguments.date1),'dateFormat(trim(arguments.date1),'yyyy/mm/dd')','[default value]')/>
<cfset sigDate2 = iif(isDate(trim(arguments.date2),'dateFormat(trim(arguments.date2),'yyyy/mm/dd')','[default value]')/>
<cfset meetDate = iif(isDate(trim(URLDecode(arguments.meetingDate),'dateFormat(trim(URLDecode(arguments.meetingDate),'yyyy/mm/dd')','[default value]')/>
or (test dates)
<cfif isDate(trim(arguments.date1)) and isDate(trim(arguments.date2)) and isDate(URLDecode(arguments.meetingDate))>
<cfset sigDate1 = dateFormat(trim(arguments.date1),'yyyy/mm/dd')/>
<cfset sigDate2 = dateFormat(trim(arguments.date2),'yyyy/mm/dd')/>
<cfset meetDate = dateFormat(URLDecode(arguments.meetingDate),'yyyy/mm/dd')/>
<cfelse>
<--- error code --->
</cfif>
or (use try block)
<cftry>
<cfset sigDate1 = dateFormat(trim(arguments.date1),'yyyy/mm/dd')/>
<cfset sigDate2 = dateFormat(trim(arguments.date2),'yyyy/mm/dd')/>
<cfset meetDate = dateFormat(URLDecode(arguments.meetingDate),'yyyy/mm/dd')/>
<cfcatch type="expression">
<--- error code --->
</cfcatch>
</cftry>

Can I store a struct in a Coldfusion session variable?

I'm passing a struct to a CF Custom Tag. I'd like the CFM page that is this custom tag to assign this struct to a dynamically created session variable. Creating the session variable works when assigning it to a simple value such as a number, but fails when assigning it to the struct in the way I'm doing it below.
<cfset Evaluate("SESSION.myVar#ATTRIBUTES.count# = #ATTRIBUTES.myStruct#")>
I thought this was possible, but when I try to do so I get an error:
Complex object types cannot be converted to simple values.
This is how the struct is created:
<cfset testStruct = StructNew()>
<cfset testStruct.something = 2>
And passed through the custom tag:
<cf_myTag myStruct="#testStruct#" count="#i#">
I think the Evaluate portion is messing things up here.
As Leigh says, use array notation rather than Evaluate() to create your dynamically named session variable:
<cfset SESSION[ "myVar" & ATTRIBUTES.count ] = ATTRIBUTES.myStruct>
Yes you can,
Just use the duplicate method
<cfset SESSION.myVar = duplicate(ATTRIBUTES.myStruct) />
yes, you can just do the following:
note I'm using a cflock here to avoid any potential race conditions.
<cflock scope="session" throwontimeout="true" timeout="5" type="exclusive">
<cfset session["myVar" & ATTRIBUTES.count] = attributes.myStruct />
</cflock>
The issue above is the evaluate statement. It's trying to evaulate the structure as a simple value in the string, and then evaluate the string.
You can get around evaulate entirely. The reason is you want a dynamically named session variable?

Cast as integer in ColdFusion; sanitizing variables

I'm rusty at ColdFusion, I've been used to PHP for so long. What I want to do is something like this:
<?php
$id = (isset($_GET['id'])) ? (int)$_GET['id'] : 0;
?>
Basically, check for a url parameter called id and if it exists make sure it's an integer so I can safely use it in database queries. If it ends up zero, that's fine too.
I have:
<cfscript>
if (IsDefined("URL.id") AND IsNumeric(URL.id)) {
id = int(URL.id);
} else {
id = 0;
}
</cfscript>
This is working, but is awfully messy. Is there a better way to do this?
Recent versions of ColdFusion also have a ternary conditional operator:
<cfset id = (structKeyExists(URL, "id") and isNumeric(URL.id)) ? int(URL.id) : 0>
I would use cfparam. I'd also scope explicitly, but that's not necessary. I wouldn't use the IIF() function, because it makes use of evaluate(), which can be problematic, I'd also avoid DE() for the same reason. In this case, it won't be an issue, but I avoid them on general principle in any situation where it's not absolutely necessary. I've been using CF for a few years now, and it hasn't been necessary yet.
<cfparam name="url.id" default="0" />
<cfif isNumeric(url.id)>
<cfset local.id = int(url.id) />
<cfelse>
<cfset local.id = 0 />
</cfif>
To me, the simplest way to ensure your variable is an integer is to wrap the variable in val().
It attempts to parse the string and extract any integer found (at the beginning of the string). If none is found it returns 0.
If TestValue = "234A56?7'", Val(TestValue) returns 234.
If TestValue = "234'5678'9?'", Val(TestValue) returns 234.
If TestValue = "BG234", Val(TestValue) returns the value 0, (not an error).
If TestValue = "0", Val(TestValue) returns the value 0, (not an error).
See http://cfquickdocs.com/cf8/#Val
Apologies for raising an old thread but came up with this same question and found a simple solution that might help others with this issue
NumberFormat(URL.id)
There are also various masks that you can specify in different scenarios
ColdFusion Reference
A formatted number value:
If no mask is specified, returns the value as an integer with a thousands separator.
If the parameter value is "" (an empty string), returns 0.
http://help.adobe.com/livedocs/coldfusion/8/htmldocs/help.html?content=functions_m-r_08.html
You might also look into cfparam.
<cftry>
<cfparam name="url.id" default="0" type="integer">
<cfcatch>
<!--- log? etc --->
<cfset url.id = 0>
</cfcatch>
</cftry>
You can use IIF. It's cool.
<cfset id = IIf(IsDefined("URL.id") AND Int(URL.id), Int(URL.id), DE("0"))>

Resources