Check values in a list are all identical - coldfusion

Ok here's a thing, I have a form which when submitted can only update a table when a particular checkbox form variable values are identical, if one is different then it should proceed to update the table. So basically the user is selecting different rows and hitting the submit button.
So for example a good submission would be
form.claimid = 12,12,12,12,12
a bad submission would be
form.claimid = 1,5,77,33,4,
I'm not sure how to check in a list if all the values in the form.claimid list are identical or not?
I would appreciate any ideas on this.

You can also use CF's native ListRemoveDuplicates() if the version is sufficient (CF10, Railo/Lucee 4)
https://wikidocs.adobe.com/wiki/display/coldfusionen/ListRemoveDuplicates
<cfif ListLen(ListRemoveDuplicates(mylist)) eq 1>
I'll leave this as an alternate means for older CFs.
I'm not sure how to check in a list if all the values in the form.claimid list are identical or not?
There are a couple ways, most of which involve looping, but I'm going to show you a regular expression that can do this. We're going to get the first value using ListFirst, and use a ReReplace on that value to see if every other value matches.
I use a loop here but only as a demonstration.
<cfoutput>
<cfset mylist = "11,22,33,44|44,44,33,44|557,557,557">
<cfloop list="#mylist#" index="m" delimiters="|">
<cfset matchele = listfirst(m)>
<cfset eradicate = rereplace(m,"(?:(?:^|,)#matchele#(?=,|$))+","","ALL")>
"#m#", "#matchele#", "#eradicate#"<br />
</cfloop>
</cfoutput>

If you're stuck on CF 9 or lower, you could loop over the list and put the elements into a struct:
<cfset list_coll = structNew() />
<cfloop list="#mylist#" index="myitem">
<cfset list_coll[myitem] = "dummy" />
</cfloop>
<cfif structCount(list_coll) EQ 1>
<!--- This is good --->
<cfelse>
<!--- This is bad --->
</cfif>
The reason this works is that structs can't have duplicate keys.

Related

Coldfusion Complex Construct

I am trying to construct a coldfusion conditional statement that looks for incremental form ID checkboxes to have been selected. All checkboxes are defined as Component[component number]. I have established a loop that is looking for a URL variable that is different for every form that calls on the condition as seen below. The issue I am having is that I recieve an error when executing that tells me "Complex constructs are not supported with function parameterexists."
Clearly it has to do with the dynamic nature of the parameterexists statement, but I do not fully know what this means. Can anyone explain this and also offer a solution? I am fairly new to coldfusion and coding, so take it easy on me.
<cfloop from="1" to="#URL.loopcounter#" index="loopvar">
<cfif parameterexists(Form.Component#loopvar#)>
INSERT INTO Results (MP_Barcode, Reworked, Reworked_By)
VALUES ('#Form.MontaplastBarcode#', 'YES', '#URL.BadgeNumber#')
</cfloop>
<cfoutput>
<p class="success">YOUR REWORK HAS BEEN SUBMITTED SUCCESSFULLY.</p>
</cfoutput>
<cfelse>
<p class="error">NO REWORK WAS SUBMITTED. NO COMPONENTS SELECTED.</p>
</cfif>
Depending on the form that calls on this action, the URL loopcounter variable could range from 1 to 50.
To answer the question, there are several ColdFusion functions that won't allow you to create a dynamic name before the function evaluates it. parameterExists() was one of those. Both isDefined() and structKeyExists() will allow dynamic variables. So will the member function of structKeyExists() > structName.keyExists("theKey").
Again, if you are new to ColdFusion, I'd simply pretend you never saw parameterExists(). I believe it has been listed as "deprecated" since CF 4.5 or somewhere around there. That's almost 20 years ago. That function has actually become somewhat of a joke about how Adobe never really throws away their trash.
As I pointed out above, I'd get rid of it completely and go with structKeyExists(). I also don't know what your whole page is doing, but with the code you provided, I'd change it to something like this:
<cfloop from="1" to="#url.loopcounter#" index="loopvar">
<cfoutput>
<cfif structKeyExists(form,"Component#loopvar#")>
<!--- SANITIZE INPUTS --->
<cfset inMontplastBarcode = sanitizingFunction(FORM.MontaplastBarcode)>
<cfset inBadgeNumber = sanitizingFunction(URL.BadgeNumber)>
<!--- Now use sanitized inputs in query with queryparams --->
<cfquery name="InsertStuff" datasource="myds">
INSERT INTO Results (MP_Barcode, Reworked, Reworked_By)
VALUES (
<cfqueryparam value="#inMontaplastBarcode#" cfsqltype="cf_sql_varchar" maxlength="50">
, 'YES'
, <cfqueryparam value="#inBadgeNumber#" cfsqltype="cf_sql_varchar" maxlength="20">
)
</cfquery>
</cfif>
</cfoutput>
</cfloop>
In your database, Reworked should be a boolean datatype. It appears that it may be a 'Yes' or 'No' string. A true boolean will be a) smaller and b) easier to validate. In the cfqueryparams, if you are using a cf_sql_varchar datatype, make sure you set an appropriate max length. You'll need to look at the available CF datatypes and see how they match up to your database datatypes. (Also see https://cfdocs.org/cfqueryparam)
For your sanitizingFunction() that you'll use to sanitize your input variables, you'll want to write a function that will follow through the steps to clean up your variables to strip out unsafe characters or other things you don't want. That is an entirely different, extremely large topic all on its own.
In your form, name your checkboxes simpler. Like reworked01 through reworked50.
On the action page use cfparam to default them to zero (since html forms don't post unchecked boxes):
<cfloop from="1" to="#url.loopCounter#" index="i">
<cfparam name="form.reworked#numberFormat(i, 00)#" default="0">
</cfloop>
Then instead of fumbling with whether or not a variable exists, you can instead look for the value:
<cfloop from="1" to="#url.loopCounter#" index="i">
<cfif evaluate("form.reworked"&i) eq 1>
<!--- some logic here --->
<cfelse>
<!--- some other logic here --->
</cfif>
</cfloop>

Coldfusion limit cfloop to 10

I'm working with quite a large array of items in a cfloop. I would like to pare this down and add pagination. Is there anyway in my cfloop to limit the array to the first 10?
I have
<cfloop array="#qryItems#" index="index">
I have tried turning it into a condition loop with no luck and a few other things. I haven't touched coldfusion in a while and am a little rusty. Google is not helping haha
I have tried
<cfloop from="1" to="10" array="#qryItems#" index="index">
and have also tried max_rows
<cfloop maxrows="10" array="#qryItems#" index="index">
each time I get the error message
"Attribute validation error for tag CFLOOP."
<cfloop from="1" to="10" index="index">
<!--- Then do your business with array elements qryItems[index], that is, with qryItems[1], qryItems[2],..., qryItems[10] --->
</cfloop>
There is no combination of attributes for cfloop to accomplish what your expecting. As BKBK suggested, you'll need to use a from/to loop to output a select group of records. If I understand your requirements correctly, I would update your cfloop with a new index variable as well, and then set the old variable by referencing the array element.
The two cfloops below output the same data, with the second displaying only the records in the pagination range.
<cfset qryItems = [1,2,3,4,5,6,7,8,9,10,'a','b','c','d'] />
<cfoutput>
<!--- Current loop: Outputs all records --->
<cfloop array="#qryItems#" index="index">
#index#
</cfloop>
<cfset paginationStart = 1 />
<cfset paginationEnd = 10 />
<!--- Only the range of of records requested --->
<cfloop from="#paginationStart#" to="#paginationEnd#" index="indexNumber">
<cfset index = qryItems[indexNumber] />
<!--- code remain the same --->
#index#
</cfloop>
</cfoutput>

Use FindNoCase to find url string

I've search around and find some valuable info. about FindNoCase but I have not yet found the answer to this specific question.
I'm using FindNoCase to find "/us/" in the url and then process some code. This works fine for one country site.
<cfif FindNoCase("/us/",#cgi.SCRIPT_NAME#)>
Process some code here.
</cfif>
My question is: Is there a way to find the piece of the url, "/xx/", for multiple country sites and process the same code between the cfif tags? For example "/us/", "/ca/", "/mx/", etc.
Hopes this makes sense.
If searching for multiple different codes among a string, I'd use REFindNoCase. Make a regex like so (/us/)|(/ca/) which would look for /us/ or /ca/ and per the documentation (http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7e99.html) you can return the sub-expressions and reference them.
No looping required.
REFindNoCase("(/us/)|(/ca/)", URL, 1, true)
To reference the strings you would do:
<cfset URL = 'domaim.com/page/us/' />
<cfset match = REFindNoCase("(/us/)|(/ca/)", URL, 1, true) />
<cfif arrayLen(match) GT 0>
<cfset value = Mid(URL,match.pos[1],match.len[1]) />
<cfswitch expression="#value#">
<cfcase value="/us/">
<!--- Do something for US match --->
</cfcase>
<cfcase value="/ca/">
<!--- Do something for CA match --->
</cfcase>
<!--- ETC --->
</cfswitch>
<cfelse>
<!--- Do something if no match found --->
</cfif>
In this case, value would equal /us/. Or it should anyway. I'm writing all of this here and not actually testing on my server. You'd have to adjust this if you want to cover multiple matches in a string.
If I'm understanding your question correctly, you want to process the SAME code for several countries, if detected in the URL. You could just create a database of country codes you want to process a certain way (CountryTableXYZ), query it, then loop through that query so it'll search the URL for each entry you have in the table.
<cfloop query="CountryQuery">
<cfif FindNoCase("#countryCode#",#cgi.SCRIPT_NAME#)>
Process some code here.
</cfif>
</cfloop>
At least that's how I interpret it. If I'm not correct please let me know or clarify your initial post.

How to store many items of data per SESSION?

I have a query called "rsUserRights" which returns User Rights like such:
UserID | Entity | Right
-----------------------
1 Note Create
1 Note Edit
1 Note Delete
This means that UserID '1' can create, edit, or delete a Note object.
All I want to do this store these permissions in a SESSION array so that the web applications know all the time what rights the logged in User has. So when a User is looking at a Note object in my applciation, the correct option to Create, Edit, or Delete will be available depending on what rights this User has.
The application needs to know what object the user has a right to, and then what is that right. Some users may not have rights expect read-only. How do I store this Entity-Right key-value pair in a ColdFusion structure?
All I have managed to do so far is this:
<cfset SESSION.Auth.UserRights = StructNew()>
<cfloop query="rsUserRights">
<cfset SESSION.Auth.UserRights.#rsUserRights.Entity#>
<cfset SESSION.Auth.UserRights.#rsUserRights.Entity#.#rsUserRights.Right#>
</cfloop>
Would the above work? Then using structkeyexits to find value-pairs? The problem I can see is that I could end up with a shed load of SESSION variables because the user may have hundreds of rights to hundreds of entities/objects. It will therefore create hundreds of SESSION variables and crash my server?
FIRST ATTEMPT SOLUTION
<cfset SESSION.Auth.UserRights = StructNew()>
<cfloop query="rsUserRights">
<cfset SESSION.Auth.UserRights[rsUserRights.Entity][rsUserRights.Right] = StructNew()>
</cfloop>
Then in my CFM pages I test for the existence of SESSION.Auth.UserRights.Note AND SESSION.UserRights.Note.Create for example
Is this ok??
That absolutely can work. Personally I would create a structure that contains the rights already defaulted to false and then on login update to true for those that match.
The reason being that you can then just check the perms instead of having to also check existence, etc. note that you should be doing a cflock but I'll leave that out of this example.
<cfset SESSION.Auth.UserRights = {}>
<cfloop index="AuthRight" list="Note,User,Documents,Application,SomethingElse">
<cfset SESSION.Auth.UserRights[AuthRight]={Create=false,Edit=false,Delete=false}>
</cfloop>
<cfloop query="rsUserRights">
<cfset SESSION.Auth.UserRights[rsUserRights.Entity][rsUserRights.Right]=true>
</cfloop>
If you are concerned about how much memory this will take, then rather than loading lots of falses into your structure, only load when true.
<cfset SESSION.Auth.UserRights = {}>
<cfloop query="rsUserRights">
<cfset SESSION.Auth.UserRights[Entity] ={}>
<cfif Right EQ 1>
<cfif SESSION.Auth.UserRights[Entity][Right] = true>
</cfif>
</cfloop>
Then all of your tests are for existence.
You could take the approach that unix web server / CHMOD permissions have. They use a single integer to denote what actions are possible for a given user.
http://www.zzee.com/solutions/unix-permissions.shtml
You could adapt your numbering to match the particular possible actions your app has - for example you might have 1 = add only, 2 = add & edit only, 3 = full add, edit & delete. Then for a user you'd just have a single digit entry for each type of object in your app. Your code might look like:
<cfset SESSION.Auth.UserRights = structNew()>
<cfset SESSION.Auth.UserRights.Note = 3>
<cfset SESSION.Auth.UserRights.User = 1>
<cfset SESSION.Auth.UserRights.Image = 2>
Checking if a user has the right permissions then involves some simple logic - depending on what actions you've got and how you've organised your numbering. Something like this:
<cfif SESSION.Auth.UserRights.Image GT 2>…
<cfif SESSION.Auth.UserRights.Note EQ 1>
If you're REALLY worried about space (and I wouldn't be) then you could just store those integers in a single list / array, and check for the integer in a particular position - but that might be tricky to keep track of as your app evolves.
<cfset SESSION.Auth.UserRights = "3,1,2,3">
<cfdump var="#listToArray(SESSION.Auth.UserRights)#">
<cfoutput>#listToArray(SESSION.Auth.UserRights)[1]#</cfoutput>

coldfusion query loop not cooperating

I'm trying to create a function to create csv files from queries. After I run the query, I'm looping through it and appending each row's fields to a StringBuffer object. To that end, I'm putting the column names into an array:
<cfset indexes = #ListToArray(Arguments.header)# />
where the argument is currently a string like:
"col1, col2, col3...."
I've verified that both the query and the array are what they should be by dumping.
The trouble comes when looping through the query results. Given:
<cfset indexes_length = #ArrayLen(indexes)# />
<cfloop query="query_for_csv">
<cfloop index="i" from="1" to="#indexes_length#">
<cfset attr = #indexes[i]# />
<cfset sbOutput.Append(
"#query_for_csv[attr][query_for_csv.CurrentRow]#") />
</cfloop>
</cfloop>
Only the first value of the first row is output before I get the error message:
[Table (rows 10 columns col1, col2, col3):
[col1: coldfusion.sql.QueryColumn#6f731eba]
[col2: coldfusion.sql.QueryColumn#6ee67e7f]
[col3: coldfusion.sql.QueryColumn#5c6647cb]
is not indexable by col2
If I replace the variable #attr# with the literal "col2":
#query_for_csv['col2'][query_for_csv.CurrentRow]#
then the loop sails through with no problem, and spits out all the values indexed by 'col2'. Any ideas?
I would guess it's the spaces in your header list that is the problem, so probably this would work:
<cfset attr = trim(indexes[i]) />
However, since you're not using them, you probably don't need that and can just do this...
<cfloop query="QueryName">
<cfloop index="CurCol" list=#QueryName.ColumnList# >
<cfset sbOutput.Append(
QueryName[CurCol][QueryName.CurrentRow]
)/>
</cfloop>
</cfloop>
p.s.
You'll note here that there's only one pair of hashes - there only needs to be one pair in your original code snippets too (in the to attribute) - the rest are unnecessary noise.
As has already been said before, try to avoid spaces before or after a list element.
In case you want to compare notes, check out the approach Ben Nadel chose to implement such a Query2CSV converter: http://www.bennadel.com/blog/1239-Updated-Converting-A-ColdFusion-Query-To-CSV-Using-QueryToCSV-.htm