Last active
March 4, 2016 04:12
-
-
Save timmaybrown/7226809 to your computer and use it in GitHub Desktop.
Here is a component that extends Ben Nadel's JSON Serializer CFC (http://www.bennadel.com/blog/2505-JsonSerializer-cfc-A-Data-Serialization-Utility-For-ColdFusion.htm) and uses the jsonUTIL project in lieu of native CF serialization to fix some known issues. This approach uses a CFDirectory call to find all my persistent CFCs (in this case they …
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment