Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Coldfusion: Nested Loop on api call Array & Struct

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

like image 799
M.A Avatar asked Apr 08 '16 22:04

M.A


2 Answers

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.

like image 107
Beginner Avatar answered Oct 23 '22 11:10

Beginner


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 ! ....

like image 1
M.A Avatar answered Oct 23 '22 10:10

M.A