Skip to content

Instantly share code, notes, and snippets.

@iknowkungfoo
Created May 9, 2018 16:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iknowkungfoo/b0bedccbca069c736a6447ec55a98f50 to your computer and use it in GitHub Desktop.
Save iknowkungfoo/b0bedccbca069c736a6447ec55a98f50 to your computer and use it in GitHub Desktop.
GO-1665
/**
* @author Adrian J. Moreno
* @website http://iknowkungfoo.com
* @Twitter: @iknowkungfoo
* @hint: A custom JSON render object for ColdFusion queries.
* @Repo: https://github.com/iknowkungfoo/cfquery-to-json
* @version 4.0
* @requirements ColdFusion 9.0+ or Railo 4+
* @BlogPost: http://cfml.us/Ce
*/
component output="false" accessors="true" {
/**
* @required true
* @setter false
* @hint The query object to convert to JSON.
*/
property query data;
/**
* @required false
* @default "json"
* @hint Sets the content-type for the response.
*/
property string contentType;
/**
* @required false
* @default true
* @hint Prefix the content with keys.
*/
property boolean dataHandle;
/**
* @required false
* @default "data"
* @hint The key for the data contained in the response.
*/
property string dataHandleName;
/**
* @required false
* @default true
* @hint Return data as
* true: an array of objects with data in name/value pairs
* false: an array of arrays with data as unnamed elements
* @example true: [{"id": 1, "value": "yes"}], false: [["1", "yes"]]
*/
property boolean dataKeys;
/**
* @required false
* @default false
* @hint Data return formst, overrides dataHandle property.
* true: return data content only, setDataHandle(false)
* false: return standard data packet, setDataHandle(true)
*/
property boolean dataOnly;
/**
* @required false
* @default "lower"
* @hint return data keys in "upper"- or "lower"-case.
*/
property string dataKeyCase;
/**
* @required false
* @default "GET,POST"
* @hint Restrict request to a list of HTTP Request Methods.
*/
property string httpRequestMethods;
/**
* Setup JSON response packet.
* @return ArrayCollection
*/
public ArrayCollection function init() {
variables.stData = {
"success" = true
, "message" = "Array Collection created."
, "meta" = {
"offset" = 0
, "pageSize" = 0
, "totalRecords" = 0
}
, "data" = []
};
// CF 9 Hackery
setContentType("json");
setDataHandle(true);
setDataHandleName("data");
setDataKeys(true);
setDataOnly(false);
setDataKeyCase("lower");
setHttpRequestMethods("GET,POST");
return this;
}
/**
* Setup query object to convert with related data as needed.
* @param required query data Query Object
* @param numeric offset Query record offset
* @param numeric pageSize Query record limit
* @param numeric totalRecords Query total records is data set
* @param boolean success
* @param string message
*/
public ArrayCollection function setData( required query data, numeric offset, numeric pageSize, numeric totalRecords, boolean success, string message = "") {
variables.data = arguments.data;
variables.stData.meta["offset"] = structKeyExists(arguments, "offset") ? arguments.offset : 0;
variables.stData.meta["pageSize"] = structKeyExists(arguments, "pageSize") ? arguments.pageSize : arguments.data.recordcount;
variables.stData.meta["totalRecords"] = structKeyExists(arguments, "totalRecords") ? arguments.totalRecords : arguments.data.recordcount;
configureDataMessage(arguments.message);
if (structKeyExists(arguments, "success")) { setSuccess(arguments.success); }
return this;
}
/**
* Overrides the DataHandle property. Returns on the data array.
* @param required boolean dataOnly
*/
public ArrayCollection function setDataOnly(required boolean dataOnly ) {
setDataHandle(!arguments.dataOnly);
return this;
}
/**
* Reset data to an empty query object.
* @param required array columns Array of columns from original query object.
*/
public ArrayCollection function resetData(required array columns) {
setData(data: querynew(arrayToList(arguments.columns)));
return this;
}
/**
* Was the query successful or not?
* @param required boolean success
*/
public ArrayCollection function setSuccess(required boolean success) {
variables.stData.success = arguments.success;
return this;
}
public boolean function getSuccess() {
return variables.stData.success;
}
/**
* Set a message to be returned to the client.
* @param required string message
*/
public ArrayCollection function setMessage(required string message) {
variables.stData.message = arguments.message;
return this;
}
/**
* Was the query successful or not?
* @param required numeric totalRecords
*/
public ArrayCollection function setTotalRecords(required numeric totalRecords) {
variables.stData.meta.totalRecords = arguments.totalRecords;
return this;
}
public numeric function getTotalRecords() {
return variables.stData.meta.totalRecords;
}
/**
* Set other data in the meta object. Will not overwrite default keys.
* @param required string key meta struct key
* @param required any value meta struct key value
*/
public ArrayCollection function setMetaKey(required string key, required any value) {
if (!structKeyExists(variables.stData.meta, arguments.key)) {
variables.stData.meta[arguments.key] = arguments.value;
}
return this;
}
/**
* Change the existing columns names of the query object to a supplied array.
* @param required array names Array of columns names, must match original column order and length
* @return ArrayCollection
*/
public ArrayCollection function changeColumnNames( required array names ) {
if (!arrayIsEmpty(arguments.names)) {
var aOriginalNames = getData().getColumnNames();
if (arraylen(aOriginalNames) NEQ arrayLen(arguments.names)) {
resetData(aOriginalNames)
.setSuccess(false)
.setMessage("Requested column names array length does not match the number of query columns.")
.setMetaKey("originalNames", aOriginalNames)
.setMetaKey("requestedNames", arguments.names);
} else {
getData().setColumnNames(arguments.names);
}
}
return this;
}
private void function configureDataMessage(string message = "") {
local.message = "ArrayCollection was populated.";
if (arguments.message IS NOT "") {
local.message = arguments.message;
} else {
switch(getTotalRecords()) {
case 0:
local.message = "No records were found.";
break;
case 1:
local.message = "1 record was found.";
break;
default:
local.message = getTotalRecords() & " records were found.";
break;
}
}
setMessage(local.message);
}
/**
* Render the collection data structure as JSON
* @return json
*/
public string function $renderdata() {
if (getSuccess()) {
var aData = [];
if (getDataKeys()){
aData = arrayOfStructs();
} else {
aData = arrayOfArrays();
}
if (getDataHandle()) {
variables.stData[getDataHandleName()] = aData;
return serializeJSON(variables.stData);
} else {
return serializeJSON(aData);
}
} else {
return serializeJSON(variables.stData);
}
}
/**
* Valdiates this is a proper Ajax reqeust.
* @return boolean
*/
public boolean function isAjaxRequest(string httpRequestMethods) {
var headers = getHttpRequestData().headers;
var validRequest = structKeyExists(headers, "X-Requested-With") and (headers["X-Requested-With"] eq "XMLHttpRequest");
if (arguments.httpRequestMethods IS NOT "") {
setHttpRequestMethods(arguments.httpRequestMethods);
}
if (validRequest) {
validRequest = validateHttpRequestMethods();
} else {
setSuccess(false);
setMessage('400 Bad Request');
}
return validRequest;
}
/**
* Valdiates this is an allowed HTTP Request Method.
* @return boolean
*/
public boolean function validateHttpRequestMethods() {
var validRequest = false;
if (listFindNoCase(getHttpRequestMethods(), cgi.REQUEST_METHOD) GT 0) {
validRequest = true;
} else {
setSuccess(false);
setMessage('405 Method Not Allowed');
}
return validRequest;
}
/**
* Returns the column list ordered alphabetically and in the case requested.
* @return string
*/
private string function getColumnList() {
var columns = listSort( getData().columnlist, "textnocase" );
if ( getDataKeyCase() IS "lower" ) {
return lcase( columns );
} else {
return ucase( columns );
}
}
/**
* Convert n query object to an array of structs.
* @return array
*/
private array function arrayOfStructs() {
var results = [];
var temp = {};
var q = getData();
var rc = q.recordCount;
var fields = listToArray(getColumnList());
var fc = arrayLen(fields);
var x = 0;
var y = 0;
var fieldName = "";
for ( x = 1; x LTE rc; x++ ){
temp = {};
for ( y = 1; y LTE fc; y++ ) {
fieldName = fields[y];
temp[fieldName] = q[fieldName][x];
}
arrayAppend( results, temp );
}
return results;
}
/**
* Convert a query object to an array of arrays.
* @return array
*/
private array function arrayOfArrays() {
var results = [];
var temp = [];
var q = getData();
var rc = q.recordCount;
var fields = listToArray(getColumnList());
var fc = arrayLen(fields);
var x = 0;
var y = 0;
for ( x = 1; x LTE rc; x++ ) {
temp = [];
for ( y = 1; y LTE fc; y++ ) {
arrayAppend( temp, q[fields[y]][x] );
}
arrayAppend( results, temp );
}
return results;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment