• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

cfif isdefined ... AND ...

Contributor ,
Mar 31, 2019 Mar 31, 2019

Copy link to clipboard

Copied

I have the following cfif statement:

<cfif status.datetime NEQ "" AND dateDiff('d',status.datetime,now()) GT 1 >

It works however in rare occasions status.datetime might not be defined. When I change it to:

<cfif isdefined("status.datetime") AND status.datetime NEQ "" AND dateDiff('d',status.datetime,now()) GT 1 >

it stops working. What am I doing wrong?

Thanks in advance for any help.

Gary

Views

1.6K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Mar 31, 2019 Mar 31, 2019

Copy link to clipboard

Copied

Add an isDate() or isValid("date") to your statement prior to comparing it to ensure that value is a "date".

While "" isn't a valid date/time value, the variable could also be NULL if returned from a database query.  (When returned from the database, the value is almost always NULL versus empty/blank.)

<cfif isdefined("status.datetime") AND isDate(status.datetime) AND dateDiff('d',status.datetime,now()) GT 1>

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Mar 31, 2019 Mar 31, 2019

Copy link to clipboard

Copied

Thanks.  isDate() is a better way to check for the valid date then "". My problem with the isdefined not working is "status" appeared in two different queries.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Apr 01, 2019 Apr 01, 2019

Copy link to clipboard

Copied

For some reason, there has been a long established issue with isDefined() and I would recommend not using it for anything.  Much more precise and less prone to error is StructKeyExists().

<cfswitch expression="#StructKeyExists(status,'datetime')#">

     <cfcase value="yes">

          <!--- successful code here --->

     </cfcase>

</cfswitch>

HTH,

^ _ ^

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 03, 2019 Apr 03, 2019

Copy link to clipboard

Copied

Indeed, WolfShade

Perhaps also something like

<cfif structKeyExists(status, "datetime") AND isDate(status.datetime) AND dateDiff('d',status.datetime,now()) GT 1>

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 03, 2019 Apr 03, 2019

Copy link to clipboard

Copied

IsDate(), or isValid("date", status.datetime), are recommended because the value could be NULL which is NOT the same as "" (an empty string).   If you use CFLint or Adobe Code Analzyer, you'll be advised to use isValid("date") instead of isDate().

Regarding StructKeyExists, I'd use it if you know the scope exists... otherwise you'll also need to check and see if the scope exists (using isDefined) and then check to determine it's the correct variable type.  If the variable isn't a struct or a query, you'll get an error if you attempt to use StructKeyExists.  (I had another programmer once use the same variable name and a struct was overwritten as non-struct.)

I've been using isDefined() since CF3 and haven't encountered any issues with the way that I use it.  I know that it can guess the incorrect scope(eg, variables, form, url, cgi), but I've always provided a fully scoped variable so there's less chance of it evaluating the wrong value.  (NOTE: It's still possible in the case that a URL/FORM value has a dot "." in the passed variable name.)

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Apr 03, 2019 Apr 03, 2019

Copy link to clipboard

Copied

One of the reasons why I prefer StructKeyFind over isDefined is because one is forced to use the scope.  You _can_ use scope in isDefined, but most of the time when I'm wrenching on someone else's code (like a dev who went to another job) I've seen no scope used in isDefined, which means that it's scrolling through all the scopes looking to see if the variable is declared in them.

Jamo wrote

If the variable isn't a struct or a query, you'll get an error if you attempt to use StructKeyExists.

Huh?  Basically all scopes are structs.  Unless you mean that you're creating a scope (not sure one can?) that CF doesn't already contain.  I've never tried that.  Never needed to.  To find something in the variables scope, use it:

<cfif StructKeyExists(variables,"myVarName")>

I don't understand your assessment that if something isn't a struct or query then StructKeyExists will throw an error.  Could you provide an example?

V/r,

^ _ ^

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 03, 2019 Apr 03, 2019

Copy link to clipboard

Copied

I agree w/using scopes.  We've had interesting things happen in the past when we didn't use scopes and crossed oure fingers hoping that ColdFusion would use the correct Form.ID, URL.ID or myQuery.ID.

Since I scope almost everything, I work with a lot of objects.  If I wanted safely use "MyStruct.House.Address.Shipping", it's a lot easier to use isdefined("MyStruct.House.Address.Shipping") versus having to verify everything:

StructKeyExists(MyStruct, "House") AND isStruct(MyStruct.House) AND StructKeyExists(MyStruct.House, "Address") AND isStruct(MyStruct.House.Address) AND StructKeyExists(MyStruct.House.Address, "Shipping")

NOTE: As a shortcut, I wrote a ExistsLen() UDF in 2017 that performs an isDefined() check and then also checks for length/arraylen/structcount/recordcount.  We've been using it in production without any issues.  (Please review and let me know if you think it can be improved.)

Regarding CF errors for non-structs when using StructKeyExists(), pretend like you aren't fully sure what is being returned and whether sub-keys exist or not.  Here's a quick proof-of-concept; only char (?), query & struct data types return a yes/no response without throwing an error.

Here's a TryCF URL:

https://www.trycf.com/gist/7a6b6222aae308b677be656f6831c59f

<CFSET Tests = {

    "boolean" = javacast("boolean", 1),

    "double" = javacast("double", 1),

    "float" = javacast("float", 1),

    "int" = javacast("int", 1),

    "long" = javacast("long", 1),

    "string" = javacast("string", 1),

    "null" = javacast("null", ""),

    "byte" = javacast("byte", 1),

    "bigdecimal" = javacast("bigdecimal", 1),

    "char" = javacast("char", "1"),

    "short" = javacast("short", 1),

    "struct_Yes" = {"abc"=123},

    "struct_No" = {"zyz"=123},

    "query_Yes" = QueryNew("abc", "varchar"),

    "query_No" = QueryNew("xyz", "varchar")

}>

<CFSET SortedKeys = ListSort(StructKeyList(Tests), "textnocase")>

<CFOUTPUT>

    <CFLOOP LIST="#SortedKeys#" INDEX="thisTest">

          <div>#ThisTest# = <CFTRY>#StructKeyExists(Tests[thisTest], "abc")#<CFCATCH>ERROR</CFCATCH></CFTRY></div>

    </CFLOOP>

</CFOUTPUT>

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Apr 04, 2019 Apr 04, 2019

Copy link to clipboard

Copied

Jamo  wrote

Since I scope almost everything, I work with a lot of objects.  If I wanted safely use "MyStruct.House.Address.Shipping", it's a lot easier to use isdefined("MyStruct.House.Address.Shipping") versus having to verify everything:

StructKeyExists(MyStruct, "House") AND isStruct(MyStruct.House) AND StructKeyExists(MyStruct.House, "Address") AND isStruct(MyStruct.House.Address) AND StructKeyExists(MyStruct.House.Address, "Shipping")

But you don't _have_ to check for every iteration with StructKeyExists.

if(NOT StructKeyExists(MyStruct,'House.Address.Shipping')) is sufficient.  Anything else is superfluous.

Jamo  wrote

(Please review and let me know if you think it can be improved.)

This is the worst thing to ask of someone who is as anal-retentive, pedantic, and borderline OCD as myself. 

As far as the rest, I do my utmost to NOT be in a position where I am not sure of what is being returned.  If I've painted myself into a corner where I have to consider that what is being returned could be more than one type, I seriously step back and consider that my design may not be what it should be.  I just might have to scrap it and start over.

V/r,

^ _ ^

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 04, 2019 Apr 04, 2019

Copy link to clipboard

Copied

I work with a lot of third-party API/JSON/objects/etc and I do whatever I can to safely normalize what is returned so that I don't have to write unique ways to intepret different provider data that has been designed by someone else.

WolfShade  wrote

As far as the rest, I do my utmost to NOT be in a position where I am not sure of what is being returned.  If I've painted myself into a corner where I have to consider that what is being returned could be more than one type, I seriously step back and consider that my design may not be what it should be.  I just might have to scrap it and start over.

I think you'll need to scrap it and start over.

I've never seen StructKeyExists() test for multiple keys in any ColdFusion documentation or demo.  Every usage I've seen has always been to test for a single "key" and not multiple "keys". While your code sample appears elegant & sufficient, it just doesn't work:

https://www.trycf.com/gist/5b20fe32da06d783f6d8636abb92f0f8

NOTE:  CF2016 & CF2018 doesn't appear to be working on TryCF.com.  Copy the code and try it at https://cffiddle.org/ against the more current versions of Adobe ColdFusion.  The result is the same... StructKeyExists(MyStruct,'House.Address.Shipping') doesn't return TRUE even though it exists.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Apr 04, 2019 Apr 04, 2019

Copy link to clipboard

Copied

Was low on caffeine when I posted.  Should have been:



DANGIT.. can't copy/paste from CFFIDDLE. 

https://cffiddle.org/app/file?filepath=cae92d32-2e59-4963-a9fe-604777889a5a/40fc62d8-b1d2-45dc-afd0-...

V/r,

^ _ ^

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Apr 04, 2019 Apr 04, 2019

Copy link to clipboard

Copied

LATEST

It's definitely a lot easier when you control the variables and know what to look for every time.

In your CFFiddle (which isn't editable without generating a new unique URL), you are blindly assuming that both the "one" and "two" keys exist in the session scope and that the "two" value is a query or struct. (You can't perform StructKeyExists() on a non-query/struct object.) You defined it two lines above in the sample, so it's obviously a safe bet, but what about another script that may or may not have included this?  It's possible that "one" doesn't exist at all.

We receive JSON data from a third-party service that contains an array of objects with optional sub-objects.  (We consume a lot of real estate & weather data from third-party APIs.) In many cases, if no data exists (ie, there's no data for the key "two"), they simply won't return it in their JSON object. If they did this, it would dramatically & unnecessarily increase the size of the returned result and impact performance.

Another example where we can't exactly control the format/schema is with 3rd-party CSV.  CSV is a very loose specification.  In some cases, rows towards the end that don't have data don't have to be included... so in a CSV file w/10 column headers, it's possible for rows to contain anywhere from 1-10 delimited values.  In addition, quoted values are allowed to contain carriage returns and span multiple rows.  This issues existed in 3rdparty data that I didn't design, but was licensing and needed to consume.  We were able to consume this data using the OpenCSV java library as it was written to deal with more exceptions than existing built-in ColdFusion routines.

I've updated my demo so you can compare the results of StructKeyExists() versus IsDefined() when the data type of the object you are testing is not known or assumed and you need to test whether it exists (or is defined.)

https://www.trycf.com/gist/7a6b6222aae308b677be656f6831c59f

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Apr 04, 2019 Apr 04, 2019

Copy link to clipboard

Copied

Thanks guys! This is all great information. I inherited a craptastic portal written in 2011. There was no outline or notes, variables passed unencrypted via URL, no SSL cert, and nothing checking what was submitted in a form, etc. My first pass through it I added hundreds of <!--- This is what's happening here --->. My second pass through I encrypted/decrypted everything passed in URL etc. Third pass I encrypted everything sent to the database tables. I mean even passwords were in plain text. Now I am going through page by page and adding HTML5 patterns to forms and checking what is being submitted matches what's expected. Two months in and probably a month more to go...

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Apr 04, 2019 Apr 04, 2019

Copy link to clipboard

Copied

Sorry to hear that you took over such a lousy project!  Hopefully it won't take you too long to correct.

As far as isDefined vs StructKeyExists, I remember reading forum posts from people who were getting false positives or false negatives with isDefined.  I can't find them, now, of course (such is my luck).  But at the very least I think it really boils down to personal preference.  I'm fanatic about StructKeyExists, Jamo leans farther towards isDefined.  (shrug)

V/r,

^ _ ^

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Resources
Documentation