CFSET Invoking Function without variable - coldfusion

New pretty new with this language, started code with it this week.
So my problem is the new company that I started with uses CF11 and they mainly only code with tags. I want to know if is possible to call cfset without a variable declaration.
If not what is the better way to call functions (that don't have return) with tags?
<cfset myFunction()>
I usually call my initiate functions at cfset, but they all have returning.
<cfset something = #initSomething()#>

Yes, invoking a function without capturing the result is perfectly fine. Sadly, there used to be a lot of that syntax in older CF documentation. It gave the erroneous impression you MUST capture the result of a function (and use extra pound signs everywhere). Neither is true. Even if a function does return something, you're not required to capture the result. Only if you wish to use it for something later. You're always free to invoke a function and completely ignore the result. So both of these are valid:
<!--- 1. capture result --->
<cfset result = getTimeNow()>
<!--- 2. ignore result --->
<cfset getTimeNow()>
<!--- sample function --->
<cffunction name="getTimeNow" return="date">
<cfreturn now()>
</cffunction>
Technically, there's nothing stopping you from capturing the result of a function that doesn't return anything. However, the "result" variable will be undefined, so it really serves no purpose.
<cfset result = doNothing()>
<!--- this will error --->
<cfoutput>#result#</cfoutput>
<!--- sample function --->
<cffunction name="doNothing" return="void">
<!--- function that returns nothing --->
</cffunction>

Related

Using ColdFusion, how do I replicate a compare statement with listFind?

I'm setting up something to allow me to masquerade as another user in my system. But, I want to use listFind instead of a compare() method.
<cfif compare(session.userName, "userOne") EQ 0>
<cfset #session.userName# = "userThree">
</cfif>
In the above statement, I'm trying to conform it to a listFind, where if userOne is currently logged in, then set the session.userName to userThree. But, I'm having trouble.
What I have thus far...
<cfif #ListFind("userOne, UserTwo")#>
<cfset #session.userName# = "userThree">
</cfif>
You will need to provide two independent arguments to ListFind. At the moment you are providing one string. The list is also the first arguments and string search for is the second.
<cfif ListFind("userOne", session.userName)>
<cfset session.userName = "userThree">
</cfif>
On a side note, the hashes are only necessary for string interpolation. In other words, only when you want a variable/expression to be evaluated and inserted into a string.

Nullif - using in Coldfusion

Looking for a little help with this code. Without posting the entire file which is way to big I just need a little help with using Nullif in Coldfusion.
I could I guess use it in my SQL statment, but for the sake of learning I am wondering if it can be used when setting variables as follows :-
The code doesn't throw any errors but I'd like to know where I would place the 0 after the Nullif.
<cfif AE_C NEQ 0>
<cfset AE_P=AE_T/AE_C>
<cfset AE_A=AE/AE_C*100>
<cfset AE_B = AE-AE_C/H8*H9>
<cfset AE_D=AE/H9*H8>
<cfelse>
<cfset AE_P=ISNULL(AE_T/NULLIF(AE_C))>
<cfset AE_A=ISNULL(AE/NULLIF(AE_C*100))>
<cfset AE_B=ISNULL(AE-AE_C/NULLIF(H8*H9))>
<cfset AE_D=ISNULL(AE/NULLIF(H9*H8))>
</cfif>
Hoping it can be done this way.
IMPORTANT: Your code is not showing any error because ISNULL is masking the error.
Also NULLIF is not a valid ColdFusion function. I believe the reason why there is no error in your page because, ColdFusion ISNULL() function seems to be a very versatile one and showing some undocumented characteristics. ISNULL() does not return an error even if the expression inside it is defined or not if the expression is syntactically valid.
eg.
ISNULL(AE_T/NULLIF(AE_C)) // No error because AE_T/NULLIF(AE_C) is a valid statement.
What you could do as an alternative is the following.
The following is a bit hacky, but you can check out the function val(). It will return 0 for any string that is not a number (check the doc for more details).
NULLIF(AE_C) becomes val(AE_C).
<cfset AE_P=ISNULL(AE_T/val(AE_C))>
Still if the val() return 0, then the output of ISNULL() will be YES, because division by 0 throws error.
This is some code that was written by Ben Nadel that I've found to resolve the error, perhaps someone can assist me in how I would implement it as I just can't get my head around it.
<!---
Do SQL division with divide-by-zero protection. But this,
time, let's provide a default value if the division is
not valid.
--->
<cfquery name="qDivision" datasource="#REQUEST.DSN.Source#">
SELECT
(
ISNULL(
(45 / NULLIF( 0, 0 )),
0
)
) AS value
;
</cfquery>
<!--- Output resulting value. --->
[ #qDivision.value# ]
This is more a comment than an answer. See RRK's answer about NULLIF not being a valid ColdFusion function and ISNULL() hiding an error.
My comment is more about the logic of your operation. You don't need to do some of the steps in your <CFELSE>
Original:
<cfif AE_C NEQ 0>
<cfset AE_P=AE_T/AE_C>
<cfset AE_A=AE/AE_C*100>
<cfset AE_B = AE-AE_C/H8*H9>
<cfset AE_D=AE/H9*H8>
<cfelse>
<cfset AE_P=ISNULL(AE_T/NULLIF(AE_C))>
<cfset AE_A=ISNULL(AE/NULLIF(AE_C*100))>
<cfset AE_B=ISNULL(AE-AE_C/NULLIF(H8*H9))>
<cfset AE_D=ISNULL(AE/NULLIF(H9*H8))>
</cfif>
I'm assuming you're using the NULLIF() to prevent divide by zero error.
First, in the languages I'm familiar with, NULLIF() requires two arguments: NULLIF(a,b) so that if a is not equal to b, it will return a, otherwise it will return NULL.
That said, your cfif says that if AE_C is not 0 then do x, else do y. I'm assuming it should be <cfset AE_P=ISNULL(AE_T/NULLIF(AE_C,0))>. If you extrapolate that out, you'd get AE_T/NULLIF(0,0) == AE_T/NULL == NULL. So you can just short-circuit that block and just set AE_P=NULL. But you also have the ISNULL() function around that, so that will always be true also. And ISNULL() (except in ColdFusion) also takes 2 arguments. In CF, it returns TRUE/FALSE (or YES/NO to be pedantic). So now you've essentially done <cfset AE_P = YES/TRUE>. I'm guessing that wasn't your original intent. So ISNULL() probably isn't appropriate here. In SQL, ISNULL(a,b) would mean that if a is NULL, return b. So (in SQL) you could essentially do AE_P = ISNULL(x,0) and that would mean that if AE_C was 0, rather than getting the divide by zero error, you could just set AE_P = 0.
TLDR; There isn't a NULLIF() function in ColdFusion, so if you're trying to prevent the div0 errors, you'll have to either do it in your SQL or modify your ColdFusion sets:
<cfif AE_C NEQ 0>
<cfset AE_P=AE_T/AE_C>
<cfset AE_A=AE/AE_C*100>
<cfelse>
<cfset AE_P=0>
<cfset AE_A=0>
</cfif>
I don't know the flow of your code, so I don't know how H8 and H9 are affected by AE_C, so you may have to check those for 0 also.
But, I'd still go back to my usual belief that if these calculations are used in SQL and not really in code, then they should be done in SQL rather than being passed out to the app server and then back to the SQL. Again, though, I don't know what your code is doing, so it may be more appropriate to have those calcs in code.

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.

Constructing a CFIF statement to display content when variable value is not blank

I am trying to write an If Statement where if "session.checkout.info.abc_1Certificate_1" exists and is not blank then show it. But if "session.checkout.info.abc_1Certificate_1" is blank don't show it.
This is what I have come up with but it is not working properly..
<cfif (len(trim("session.checkout.info.abc_1Certificate_1")))>
Certificate: #session.checkout.info.abc_1Certificate_1#
</cfif>
Try this
<cfif isDefined("session.checkout.info.abc_1Certificate_1")
AND len(trim(session.checkout.info.abc_1Certificate_1))>
Certificate: #session.checkout.info.abc_1Certificate_1#
<cfelse>
session.checkout.info.abc_1Certificate_1 doesn't exist or is blank
</cfif>
You really rather want something like this:
<cfif structKeyExists(session.checkout.info,"abc_1Certificate_1") AND len(trim(session.checkout.info.abc_1Certificate_1)) GT 0>
This is saying: if there is a key called abc_1Certificate_1 in the structure session.checkout.info AND the length of the value of session.checkout.info.abc_1Certificate_1 with any padding spaces removed is greater than 0, then...
If session.checkout.info.abc_1Certificate_1 doesn't exist, then len(trim(session.checkout.info.abc_1Certificate_1)) would normally throw an error, but since ColdFusion processes the part of the statement to the left of the AND first (and short-circuits the evaluation) CF won't bother to examine the rest of the statement.

When should I use # in ColdFusion?

This has been one of the biggest obstacles in teaching new people ColdFusion.
When to use # is ambiguous at best. Since using them doesn't often create a problem it seems that most people gravitate to using them too much.
So, what are the basic rules?
I think it may be easier to say where NOT to use #. The only place is in cfif statements, and cfset statements where you are not using a variable to build a string in quotes. You would need to use the # sign in almost all other cases.
Example of where you are not going to use it:
<cfset value1 = 5>
<cfset value2 = value1/>
<cfif value1 EQ value2>
Yay!!!
</cfif>
<cfset value2 = "Four plus one is " & value1/>
Examples of where you will use #:
in a cfset where the variable is surrounded by quotes
<cfset value1 = 5>
<cfset value2 = "Four plus one is #value1#"/>
the bodies of cfoutput, cfmail, and cffunction (output="yes") tags
<cfoutput>#value2#</cfoutput>
<cfmail to="e#example.com" from="e#example.com" subject="x">#value2#</cfmail>
<cffunction name="func" output="yes">#value2#</cffunction>
in an attribute value of any coldfusion tag
<cfset dsn = "myDB"/>
<cfquery name="qryUsers" datasource="#dsn#">
<cfset value1 = 5>
<cfset value2 = 10/>
<cfloop from="#value1#" to="#value2#" index="i">
<cfqueryparam value="#value1#" cfsqltype="cf_sql_integer"/>
EDIT:
One oddball little thing I just noticed that seems inconsistent is conditional loops allow the variable name to be used with and without # signs.
<cfset value1 = 5>
<cfloop condition = "value1 LTE 10">
<cfoutput>#value1#</cfoutput><br>
<cfset value1 += 1>
</cfloop>
<cfset value1 = 5>
<cfloop condition = "#value1# LTE 10">
<cfoutput>#value1#</cfoutput><br>
<cfset value1 += 1>
</cfloop>
Here's what Adobe has to say about it:
Using number signs
String interpolation:
<cfset name = "Danny" />
<cfset greeting = "Hello, #name#!" />
<!--- greeting is set to: "Hello, Danny!" --->
Auto-escaped string interpolation in cfquery:
<cfset username = "dannyo'doule" ?>
<cfquery ...>
select u.[ID]
from [User] u
where u.[Username] = '#username#'
</cfquery>
<!--- the query is sent to the server (auto-escaped) as: --->
<!--- select u.[ID] from [User] u where u.[Username] = 'dannyo''doule' --->
<!--- note that the single-quote in the username has been escaped --->
<!--- by cfquery before being sent to the database server --->
Passing complex arguments/attributes in CFML:
<cfset p = StructNew() />
<cfset p.firstName = "Danny" />
<cfset p.lastName = "Robinson" />
<cfmodule template="modules/view/person.cfm" person="#p#">
<!--- the variable Attributes.person will be --->
<!--- available in modules/view/person.cfm --->
Passing complex arguments requires # signes only in CFML, not CFScript. In addition, you can pass any kind of value: simple values, arrays, structs, cfcomponents, cffunctions, java objects, com objects, etc.
In all these cases, the text between the # signs does not have to be the name of a variable. In fact, it can by any expression. Of course, for string interpolation, the expression must evaluate to a simple value, but for argument/attribute passing in CFML, the expression may evaluate to any complex value as well.
The #...# syntax allows you to embed an expression within a string literal. ColdFusion is unfortunately pretty inconsistent about what's a string and what's an expression. Jayson provided a good list of examples of when to use (or not use) #s.
At the risk of sounding like a wise-guy, a rule of thumb is: use # around variables or expressions only when not doing so doesn't yield the correct result. Or: if you don't need them, don't use them.
I like Jayson's answer though.
Let's start by assuming you aren't talking about cfoutput tags, cause then the answer is always, elsewhere in your code, if you are inside of quotation marks, then need to use # symbols if it's possible to actually type the value that is going to be used...so if you are in a cfloop tag setting the 'to' attribute, you could easily type 6, but if you want to use a variable you need to use the # symbols. Now if you are in a cfloop tag setting the query parameter, there is no way you could actually type the query into that attribute, there is no way to type a query, so no # symbols are needed.
Likewise in a cfdump tag, you can dump static text, so if you want to dump the contents of a variable, then you will need to use a # symbol. This problem is generally self-correcting, but I feel your pain, your students are probably frustrated that there is no "ALWAYS USE THEM" or "NEVER USE THEM" approach...sadly this isn't the case, the only thing that is true, is only one way inside of quotation marks is going to be correct. So if it isn't working look at it hard and long and think to yourself: "Could I type that value out instead of using the value contained in that variable?" If the answer is no, then the # symbols won't be needed, otherwise get your # character foo on.