Skip to content

Instantly share code, notes, and snippets.

@timmaybrown
Last active March 4, 2016 04:12
Show Gist options
  • Select an option

  • Save timmaybrown/7226809 to your computer and use it in GitHub Desktop.

Select an option

Save timmaybrown/7226809 to your computer and use it in GitHub Desktop.

Revisions

  1. timmaybrown renamed this gist Sep 24, 2014. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. Tim Brown created this gist Oct 30, 2013.
    162 changes: 162 additions & 0 deletions gistfile1.cfm
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,162 @@
    <cfcomponent extends="model.util.jsonSerializer" singleton="true">

    <cfproperty name="jsonUTIL" inject="model" />

    <cffunction name="init">
    <!---// let's init Mr. Nadel's serializer--->
    <cfset super.init()>

    <!--- FOR Reference: PROPERTIES THAT ARE AVAILABLE due to the SUPER.init() call above
    // Every key is added to the full key list.
    fullKeyList = {};
    // These key lists determine special data serialization.
    booleanKeyList = {};
    integerKeyList = {};
    floatKeyList = {};
    dateKeyList = {};
    // These keys will NOT be used in serialization (ie. the key/value pairs will not be added
    // to the serialized output).
    blockedKeyList = {};
    // When serializing values, ColdFusion has a tendency to convert strings to numbers if those
    // strings look like numbers. We will prepend the string values with this "conversion blocker"
    // so that we can force ColdFusion to make a string (this gets removed after serialization).
    START_OF_STRING = chr( 2 );
    --->

    <!--- PERSISTENT ENTITY SEARCH LOGIC --->
    <cfset var qEntities = "">
    <cfset var qModels = "">
    <!--- LET's fetch our model's this be an array of persitent cfc names,
    but I don't want to have to update the array for every new entity I add to my model's folder --->
    <cfdirectory
    action="list"
    type="file"
    listinfo="name"
    directory="#GetDirectoryFromPath( GetBaseTemplatePath() )#model\" name="qModels" />

    <cfquery name="qEntities" dbtype="query">
    SELECT Name FROM qModels WHERE Name NOT LIKE '%Service.cfc'
    AND Name NOT IN ('DummyFlash.cfc','ORMEventHandler.cfc')
    </cfquery>

    <cfset var arEntities = listToArray(valueList(qEntities.Name))>
    <!--- /END PERSISTENT ENTITY SEARCH LOGIC --->

    <!---
    UNCOMMENT IF YOU WANT TO GET ALL avail type Methods
    <cfset pMeths = GetComponentMetaData('jsonSerializer').functions>
    <cfset f = "">
    <cfloop array="#pMeths#" index="p">
    <cfif !listFindnoCase(f, p.name) && left(p.name, 2) EQ 'as'>
    <cfset f = listAppend(f, p.name)>
    </cfif>
    </cfloop>
    <cfdump var="#f#"><cfabort>
    --->

    <!--- COMPONENT METADATA LOGIC --->
    <cfscript>
    var meta = {};
    var md = {};
    // iteration to fetch all entity properties if the cfc is a persistent cfc
    for(var e=1; e <= arrayLen(arEntities); e++){
    c = listFirst(arEntities[e], '.');
    md = GetComponentMetaData("model.#c#");
    if (structKeyExists(md,'persistent')) meta[c] = md.properties;
    }
    // now let's prep the struct of property names the value of the property names are the method name available in the serializer
    // eg: toInit['userID'] = 'asInteger';
    // this will allow for dyanmic method invocation of the asInteger method now available from the inherited serailizer
    var toInit = {};
    var entityName = "";
    var entityProperties = [];
    for(entityName in meta){
    entityProperties = meta[entityName];
    for(var p=1; p <=arrayLen(entityProperties); p++){
    toInit[entityProperties[p].name] = (structKeyExists(entityProperties[p], 'ormType')) ? getSerializeMethByORMType(entityProperties[p].ormType) : "asAny";
    }
    }
    //now that the toInit structure is ready lets dynamically invoke the methods.
    // Thanks to Adam Cameron for this blogging about this little trick (http://cfmlblog.adamcameron.me/2012/09/functions-and-their-execution-context.html)
    for(propertyName in toInit) {
    this.theMethod = this[toInit[propertyName]]; //put a reference to the ACTUAL method into this static property name
    this.theMethod(key=propertyName); // now invoke the dynamic method
    }
    // now for anything else that wasn't a proper name that was custom just continue to chain calls like Mr Nadel shows in his blog post
    this
    .asInteger("adCount")
    .asString("partnerName")
    .asString("configStatus")
    ;
    </cfscript>


    <cfreturn this>
    </cffunction>

    <!------------------------------------------------------------------------
    PUBLIC METHODS
    ------------------------------------------------------------------------->

    <!--- override Mr. Nadel's serialize method and use injected jsonUTIL service in lieu of CF's serializeJSON() --->
    <cffunction name="serialize" access="public" returntype="String">
    <cfargument name="input" required="true" type="any" />

    <cfscript>
    var preparedInput = prepareInputForSerialization( input );
    var serializedInput = jsonUtil.serialize(var=preparedInput, strict="true");
    // At this point, we have the serialized response; but, the response contains unwanted
    // artifacts that were required to enforce string value integrity. Those must now be
    // removed, post-serialization.
    var sanitizedResponse = removeStartOfStringMarkers( serializedInput );
    return( sanitizedResponse );
    </cfscript>

    </cffunction>

    <!------------------------------------------------------------------------
    PRIVATE METHODS
    ------------------------------------------------------------------------->

    <cffunction name="getSerializeMethByORMType" access="private">
    <cfargument name="ormType" type="string" required="true">

    <cfscript>
    var stORMTypes = {
    "big_decimal" = "asFloat"
    ,"binary" = "asString"
    ,"blob" = "asString"
    ,"boolean" = "asBoolean"
    ,"char" = "asString"
    ,"character" = "asString"
    ,"clob" = "asString"
    ,"date" = "asDate"
    ,"double" = "asFloat"
    ,"float" = "asFloat"
    ,"int" = "asInteger"
    ,"integer" = "asInteger"
    ,"long" = "asString"
    ,"serializable" = "asString"
    ,"short" = "asString"
    ,"string" = "asString"
    ,"text" = "asString"
    ,"timestamp" = "asDate"
    ,"true_false" = "asBoolean"
    ,"yes_no" = "asBoolean"
    };
    return (structKeyExists(stORMTypes, ormType)) ? stORMTypes[ormType] : "asAny";
    </cfscript>

    </cffunction>


    </cfcomponent>