5

My function calls the SendGrid API. It returns an Array + structure. I'm writing a function to return a CFQuery dataset.

Goal I want to pass a deserialized data object to my function and get a query dataset.

Here is my working code and the output:

<cfparam name="variables.ddata" default="#structnew()#">
<!--- API Call Code here --->
<cfset arr = DESerializeJSON(returnStruct.Filecontent) />
<cfdump var="#arr#">

CFdump on call

My code:

 <cfset arrayit(arrobj= arr) >
 <cfdump var="#variables.ddata#" >
 <cffunction name="arrayit" access="public" returntype="void">
    <cfargument name="arrobj" type="array"  required="yes">
    <cfset var arr=arguments.arrobj />
    <cfloop from="1" to =   "#arrayLen(arr)#" index="i">
       <cfif isValid("string", arr[i])>
          <cfset StructInsert(variables.ddata, i, arr[i]) />
       </cfif>
       <cfif isstruct(arr[i])>
          <cfset structit(structobj = arr[i]) />
       </cfif>
    </cfloop>
</cffunction>

<cffunction name="structit" access="public" returntype="void" output="yes">
   <cfargument name="structobj" type="any" required="yes">
   <cfset  stru = arguments.structobj />
   <cfloop collection="#stru#" item="S"> 
       <cfif isValid("string", stru[S])>
          <cfset StructInsert( variables.ddata, S, stru[S]) />
       </cfif>
       <cfif isarray(stru[S])>
           <cfset arrayit(arrobj = stru[S]) >
       </cfif>
   </cfloop>
</cffunction>

Result:

Result

When I add this line in my function

<cfif isstruct(stru[S])>
    <cfset variables.ddata   =  arrayit(arrobj = stru[S]) />
</cfif>

An error occurs:

Element type is undefined in a CFML structure referenced as part of an expression.
The error occurred on line 71.

** Full Code**

    <cfsavecontent variable="returnStruct.Filecontent">
[{"date":"2016-04-05","stats":[{"type":"category","name":"5","metrics":{"blocks":1,"bounce_drops":0,"bounces":9,"clicks":4,"deferred":1,"delivered":1,"invalid_emails":8,"opens":4,"processed":1,"requests":1,"spam_report_drops":0,"spam_reports":1,"unique_clicks":3,"unique_opens":3,"unsubscribe_drops":0,"unsubscribes":9}}]}]
</cfsavecontent>

<cfset arr = DESerializeJSON(returnStruct.Filecontent) />

<cfloop from="1" to="#arrayLen(arr)#" index="i">
   <cfif isValid("string", arr[i])>
        <cfset StructInsert(variables.ddata, i, arr[i],true ) />
   </cfif>

   <cfif isstruct(arr[i])>
        <cfsavecontent variable="rr">
            <cfdump var="#arr[i]#"  label="Line 48 ERROR" >
        </cfsavecontent>
        <cfset NotifyErrorAdmin(emailBody = "#rr#"  ,emailsubject = "Line 48") />
        <cfset structit(structobj = arr[i]) />
   </cfif>
      <cfif isarray(arr[i])>
        <cfsavecontent variable="rr">
            <cfdump var="#arr[i]#"  label="Line 54 ERROR" >
        </cfsavecontent>
        <cfset NotifyErrorAdmin(emailBody = "#rr#"  ,emailsubject = "Line 54") />
        <cfset arrayit(arrobj = arr[i]) >
    </cfif>
</cfloop>
</cffunction> 

<cffunction name        =   "structit" access="public" returntype="void" output="yes">
<cfargument name        =   "structobj" type="any" required="yes">
<cfset  stru            =   arguments.structobj />

<cfloop collection="#stru#" item="S"> 
    <cfif isValid("string", stru[S])>
         <cfset StructInsert( variables.ddata, S, stru[S],true) />
    </cfif>
    <cfif isarray(stru[S])>
        <cfsavecontent variable="rr">
            <cfdump var="#stru[S]#"  label="Line 86 ERROR" >
        </cfsavecontent>
        <cfset NotifyErrorAdmin(emailBody = "#rr#"  ,emailsubject = "Line 87") />
        <cfset arrayit(arrobj = stru[S]) >
    </cfif>
 <cfif isstruct(stru[S])>
        <cfsavecontent variable="rr">
            <cfdump var="#stru[S]#"  label="Line 97 ERROR" >
        </cfsavecontent>
        <cfset NotifyErrorAdmin(emailBody = "#rr#"  ,emailsubject = "Line 97") />
        <cfset structit(structobj = stru[S]) />
   </cfif>
</cfloop>
</cffunction> 

ERRORSg3Sg4sg5sg1err

M.A
  • 448
  • 6
  • 21

2 Answers2

3

Your UDF arrayit accepts an argument of type array but when that condition is true then a struct is being passed so, the error. i.e.,

<cfif isStruct(stru[S])>

    <!--- This means stru[S] is a struct  --->
    <cfset variables.ddata = arrayit(arrobj = stru[S])>
    <!--- arrObj should be of type 'array' --->
</cfif>

So, it should be:

<cfif isStruct(stru[S])>
    <cfset variables.ddata = structit(structobj = stru[S])>
</cfif>

But, the error for this case will be different than that you have added.

Additionally,

  • StructInsert() takes an optional argument allowoverwrite which is by default false and according to docs:

if key exists and allowoverwrite = "False", ColdFusion throws an exception.

Abhishekh Gupta
  • 6,206
  • 4
  • 18
  • 46
  • hi you are right it was typeo but im still getting error even after adding over write argument. this time error bit change*** The element at position 2 of dimension 1, of array variable "ARR," cannot be found.
    The error occurred on line 48. *** line 48 ``
    – M.A Apr 09 '16 at 15:11
  • @knowledgeSeeker Better add this error to your question and remove the typos. – Abhishekh Gupta Apr 09 '16 at 15:25
  • Also, nothing to do with your question but A) do not forget to scope *all* function local variables and B) to make the functions more reusable, and avoid possible threading issues, consider passing in the structure you want to populate as an argument. Structures are passed by reference in CF. – Leigh Apr 09 '16 at 19:05
1

I just did it! :) just wanted to share my project with you guys also hope it will help someone else also...

Request if you guys find anything you feel I can improve please share.

Special Thanks for response on my post. @Beginner & @Leigh

API Call Json Return: 1

    <cfsavecontent variable="returnStruct.Filecontent">
[{"date":"2016-04-05","stats":[{"type":"category","name":"5","metrics":{"blocks":1,"bounce_drops":0,"bounces":9,"clicks":4,"deferred":1,"delivered":1,"invalid_emails":8,"opens":4,"processed":1,"requests":1,"spam_report_drops":0,"spam_reports":1,"unique_clicks":3,"unique_opens":3,"unsubscribe_drops":0,"unsubscribes":9}}]}]
</cfsavecontent>

<cfset arr = DESerializeJSON(returnStruct.Filecontent) />

CFC : 2

    <cfcomponent>
<cfparam name="variables.qryclsvar" default=""  type="any"/> 
<cfparam name="variables.qryclsvarfg" default="true"  type="any"/> 

<cffunction name="APItoquery" access="public" returntype="any">
<cfargument name        = "APIobj"          type="any"  required="yes">
<cfset var vAPIobj      = arguments.APIobj />
<cfset var APIDATA      = structnew() />
<cfset var APIDATAqr        = "" />
<cftry>
    <cfloop from="1" to="#arrayLen(vAPIobj)#" index="jj">
         <cfif  isarray(vAPIobj[jj])>
            <cfset APIDATA =  arrayit(structobj = vAPIobj[jj] ,datastruct = APIDATA) />
         </cfif>
          <cfif isstruct(vAPIobj[jj])>
            <cfset APIDATA =  structit(structobj = vAPIobj[jj],datastruct = APIDATA) />
       </cfif>

        <cfif NOT StructIsEmpty(APIDATA)>  
            <!--- Add in query object --->
            <cfset APIDATAqr = structtoquery(structobj= APIDATA) />
        <cfelse>
            <cfset APIDATAqr ="NO Data Found!" />
        </cfif>
    </cfloop>

 <cfcatch>
    <cfdump var="#cfcatch#" label="APItoquery">
 </cfcatch>
 </cftry>
<cfreturn APIDATAqr>
</cffunction>



<cffunction name        =   "arrayit"           access="public" returntype="any">
<cfargument name        =   "arrobj"            type="any"  required="yes">
<cfargument name        =   "datastruct"        type="any"  required="yes" >
<cfset  var arr         =   arguments.arrobj />
<cfset  var arrdata     =   arguments.datastruct />
<cftry>
<cfloop from="1" to="#arrayLen(arr)#" index="i">
        <cfif ArrayContains(arr, i) >
            <cfset StructInsert(arrdata, i, arr[i],true ) />

        </cfif>
        <cfif  isarray(arr[i])>
            <cfset arrdata  =   arrayit(arrobj = arr[i] ,datastruct = arrdata) >
        </cfif>
        <cfif isstruct(arr[i]) >
            <cfset stdata   =    structit(structobj = arr[i],datastruct = arrdata) />
       </cfif>
</cfloop>
 <cfcatch>
    <cfdump var="#cfcatch#" label="arrayit">
 </cfcatch>
 </cftry>
 <cfreturn arrdata>
</cffunction> 


<cffunction name        =   "structit"          access="public" returntype="any" output="yes">
<cfargument name        =   "structobj"         type="any" required="yes">
<cfargument name        =   "datastruct"        type="any"  required="yes">
<cfset  var stru        =   arguments.structobj />
<cfset  var stdata      =   arguments.datastruct />
<cftry>
    <cfloop collection="#stru#" item="S"> 
        <cfif  isarray(stru[S])>
            <cfset stdata   =   arrayit(arrobj = stru[S] ,datastruct = stdata) >
         <cfelseif isstruct(stru[S]) >
            <cfset stdata   =    structit(structobj = stru[S],datastruct = stdata) />
         <cfelse>
            <cfset StructInsert( stdata, S, stru[S],true) />

        </cfif>
    </cfloop>
 <cfcatch>
    <cfdump var="#cfcatch#" label="structit">
 </cfcatch>
 </cftry>
 <cfreturn stdata>
</cffunction> 

<cffunction name        =   "structtoquery"             access="public" returntype="any" output="yes">
<cfargument name        =   "structobj"             type="any" required="yes">
<cfset  var vstructobj      =   arguments.structobj />
<cfset var cols     = StructKeyList(vstructobj)>
<cfset var colstyp = "">
        <cftry>
            <cfif variables.qryclsvarfg EQ true>
                <cfloop from="1" to="#listlen(cols,',')#" index="L">
                    <cfset colstyp = ListAppend(colstyp,"VarChar",",")>
                </cfloop>
                <!--- Create a new query. --->
                <cfset variables.qryclsvar = queryNew(
                                        '#cols#',
                                        '#colstyp#'
                                        )>
            <cfset variables.qryclsvarfg = false>
            </cfif>   
            <cfset QueryAddRow(variables.qryclsvar, 1)>
             <cfloop collection="#vstructobj#" item="sd">
                <cfset QuerySetCell(variables.qryclsvar,    "#sd#", vstructobj[sd])>
             </cfloop>

         <cfcatch>
            <cfdump var="#cfcatch#" label="structit">
         </cfcatch>
         </cftry>
 <cfreturn variables.qryclsvar>
</cffunction> 
</cfcomponent>

CFM : 3

<cfset sgObj =  createobject("component","cfc.mycfc") />
<cfset mystruct = sgObj.APItoquery(APIobj= arr1) >
<cfdump var="#mystruct#"  label="mystruct">

MA ! ....

M.A
  • 448
  • 6
  • 21