234 attempt to fix js error Uncaught SyntaxError: Unexpected identifier 'hidden'

This commit is contained in:
2026-04-27 17:57:24 +03:00
parent 8a32a0d5f0
commit 74c073bd7e
149 changed files with 14361 additions and 8886 deletions
+1390 -1360
View File
File diff suppressed because it is too large Load Diff
+40 -50
View File
@@ -1,57 +1,47 @@
<cfcomponent output="false" hint="a helper class to decode input data">
component output="false" hint="a helper class to decode input data" {
<!--- the most basic of input handlers, available in all APIs --->
<cffunction name="getFromForm" output="false" taffy:mime="application/x-www-form-urlencoded" hint="get data from form post">
<cfargument name="body" hint="the textual request body" />
<cfset var response = {} />
<cfset var pairs = listToArray(arguments.body, "&") />
<cfset var pair = "" />
<cfset var kv = [] />
<cfset var ix = 0 />
<cfset var k = "" />
<cfset var v = "" />
public function getFromForm(body) output="false" taffy_mime="application/x-www-form-urlencoded" hint="get data from form post" {
var response = {};
var pairs = listToArray(arguments.body, "&");
var pair = "";
var kv = [];
var ix = 0;
var k = "";
var v = "";
<cfif not find('=', arguments.body)>
<cfset throwError(400, "You've indicated that you're sending form-encoded data but it doesn't appear to be valid. Aborting request.") />
</cfif>
if (!find('=', arguments.body)) {
throwError(400, "You've indicated that you're sending form-encoded data but it doesn't appear to be valid. Aborting request.");
}
<cfloop from="1" to="#arrayLen(pairs)#" index="ix">
<cfset pair = pairs[ix] />
<cfset kv = listToArray(pair, "=", true) />
<cfset k = kv[1] />
<cfset v = urlDecode( kv[2] ) />
<cfif structKeyExists( response, k )>
<cfset response[k] = listAppend(response[k], v)>
<cfelse>
<cfset response[k] = v>
</cfif>
</cfloop>
for (ix = 1; ix <= arrayLen(pairs); ix++) {
pair = pairs[ix];
kv = listToArray(pair, "=", true);
k = kv[1];
v = urlDecode(kv[2]);
if (structKeyExists(response, k)) {
response[k] = listAppend(response[k], v);
} else {
response[k] = v;
}
}
<cfreturn response />
</cffunction>
return response;
}
<!--- ============================ --->
<!--- Helpers --->
<!--- ============================ --->
private void function throwError(numeric statusCode=500, required string msg, struct headers={}) output="false" {
cfcontent(reset="true");
addHeaders(arguments.headers);
cfheader(statuscode=arguments.statusCode, statustext=arguments.msg);
abort;
}
<cffunction name="throwError" access="private" output="false" returntype="void">
<cfargument name="statusCode" type="numeric" default="500" />
<cfargument name="msg" type="string" required="true" hint="message to return to api consumer" />
<cfargument name="headers" type="struct" required="false" default="#structNew()#" />
<cfcontent reset="true" />
<cfset addHeaders(arguments.headers) />
<cfheader statuscode="#arguments.statusCode#" statustext="#arguments.msg#" />
<cfabort />
</cffunction>
private void function addHeaders(required struct headers) output="false" {
var h = '';
if (!structIsEmpty(arguments.headers)) {
for (h in arguments.headers) {
cfheader(name=h, value=arguments.headers[h]);
}
}
}
<cffunction name="addHeaders" access="private" output="false" returntype="void">
<cfargument name="headers" type="struct" required="true" />
<cfset var h = '' />
<cfif !structIsEmpty(arguments.headers)>
<cfloop list="#structKeyList(arguments.headers)#" index="h">
<cfheader name="#h#" value="#arguments.headers[h]#" />
</cfloop>
</cfif>
</cffunction>
</cfcomponent>
}
+173 -177
View File
@@ -1,199 +1,195 @@
<cfcomponent output="false" hint="a helper class to represent easily serializable data">
component output="false" hint="a helper class to represent easily serializable data" {
<cfset variables.data = "" />
<cfset variables.fileName = "" />
<cfset variables.fileMime = "" />
<cfset variables.statusCode = 200 />
<cfset variables.statusText = "OK" />
<cfset variables.miscHeaders = StructNew() />
<cfset variables.deleteFile = false />
<!--- 1= textual, 2= filename, 3= file data --->
<cfset variables.type = 1 />
<cfset variables.types = StructNew() />
<cfset variables.types[1] = "textual" />
<cfset variables.types[2] = "filename" />
<cfset variables.types[3] = "filedata" />
<cfset variables.types[4] = "imagedata" />
<cfset variables.statusTexts = StructNew() />
<cfset variables.statusTexts[100] = "Continue" />
<cfset variables.statusTexts[101] = "Switching Protocols" />
<cfset variables.statusTexts[102] = "Processing" />
<cfset variables.statusTexts[200] = "OK" />
<cfset variables.statusTexts[201] = "Created" />
<cfset variables.statusTexts[202] = "Accepted" />
<cfset variables.statusTexts[203] = "Non-authoritative Information" />
<cfset variables.statusTexts[204] = "No Content" />
<cfset variables.statusTexts[205] = "Reset Content" />
<cfset variables.statusTexts[206] = "Partial Content" />
<cfset variables.statusTexts[207] = "Multi-Status" />
<cfset variables.statusTexts[208] = "Already Reported" />
<cfset variables.statusTexts[226] = "IM Used" />
<cfset variables.statusTexts[300] = "Multiple Choices" />
<cfset variables.statusTexts[301] = "Moved Permanently" />
<cfset variables.statusTexts[302] = "Found" />
<cfset variables.statusTexts[303] = "See Other" />
<cfset variables.statusTexts[304] = "Not Modified" />
<cfset variables.statusTexts[305] = "Use Proxy" />
<cfset variables.statusTexts[307] = "Temporary Redirect" />
<cfset variables.statusTexts[308] = "Permanent Redirect" />
<cfset variables.statusTexts[400] = "Bad Request" />
<cfset variables.statusTexts[401] = "Unauthorized" />
<cfset variables.statusTexts[402] = "Payment Required" />
<cfset variables.statusTexts[403] = "Forbidden" />
<cfset variables.statusTexts[404] = "Not Found" />
<cfset variables.statusTexts[405] = "Method Not Allowed" />
<cfset variables.statusTexts[406] = "Not Acceptable" />
<cfset variables.statusTexts[407] = "Proxy Authentication Required" />
<cfset variables.statusTexts[408] = "Request Timeout" />
<cfset variables.statusTexts[409] = "Conflict" />
<cfset variables.statusTexts[410] = "Gone" />
<cfset variables.statusTexts[411] = "Length Required" />
<cfset variables.statusTexts[412] = "Precondition Failed" />
<cfset variables.statusTexts[413] = "Payload Too Large" />
<cfset variables.statusTexts[414] = "Request-URI Too Long" />
<cfset variables.statusTexts[415] = "Unsupported Media Type" />
<cfset variables.statusTexts[416] = "Requested Range Not Satisfiable" />
<cfset variables.statusTexts[417] = "Expectation Failed" />
<cfset variables.statusTexts[418] = "I'm a teapot" />
<cfset variables.statusTexts[421] = "Misdirected Request" />
<cfset variables.statusTexts[422] = "Unprocessable Entity" />
<cfset variables.statusTexts[423] = "Locked" />
<cfset variables.statusTexts[424] = "Failed Dependency" />
<cfset variables.statusTexts[426] = "Upgrade Required" />
<cfset variables.statusTexts[428] = "Precondition Required" />
<cfset variables.statusTexts[429] = "Too Many Requests" />
<cfset variables.statusTexts[431] = "Request Header Fields Too Large" />
<cfset variables.statusTexts[444] = "Connection Closed Without Response" />
<cfset variables.statusTexts[451] = "Unavailable For Legal Reasons" />
<cfset variables.statusTexts[499] = "Client Closed Request" />
<cfset variables.statusTexts[500] = "Internal Server Error" />
<cfset variables.statusTexts[501] = "Not Implemented" />
<cfset variables.statusTexts[502] = "Bad Gateway" />
<cfset variables.statusTexts[503] = "Service Unavailable" />
<cfset variables.statusTexts[504] = "Gateway Timeout" />
<cfset variables.statusTexts[505] = "HTTP Version Not Supported" />
<cfset variables.statusTexts[506] = "Variant Also Negotiates" />
<cfset variables.statusTexts[507] = "Insufficient Storage" />
<cfset variables.statusTexts[508] = "Loop Detected" />
<cfset variables.statusTexts[510] = "Not Extended" />
<cfset variables.statusTexts[511] = "Network Authentication Required" />
<cfset variables.statusTexts[599] = "Network Connect Timeout Error" />
variables.data = "";
variables.fileName = "";
variables.fileMime = "";
variables.statusCode = 200;
variables.statusText = "OK";
variables.miscHeaders = {};
variables.deleteFile = false;
variables.noDataSends204NoContent = false;
// 1= textual, 2= filename, 3= file data
variables.type = 1;
variables.types = {};
variables.types[1] = "textual";
variables.types[2] = "filename";
variables.types[3] = "filedata";
variables.types[4] = "imagedata";
variables.statusTexts = {};
variables.statusTexts[100] = "Continue";
variables.statusTexts[101] = "Switching Protocols";
variables.statusTexts[102] = "Processing";
variables.statusTexts[200] = "OK";
variables.statusTexts[201] = "Created";
variables.statusTexts[202] = "Accepted";
variables.statusTexts[203] = "Non-authoritative Information";
variables.statusTexts[204] = "No Content";
variables.statusTexts[205] = "Reset Content";
variables.statusTexts[206] = "Partial Content";
variables.statusTexts[207] = "Multi-Status";
variables.statusTexts[208] = "Already Reported";
variables.statusTexts[226] = "IM Used";
variables.statusTexts[300] = "Multiple Choices";
variables.statusTexts[301] = "Moved Permanently";
variables.statusTexts[302] = "Found";
variables.statusTexts[303] = "See Other";
variables.statusTexts[304] = "Not Modified";
variables.statusTexts[305] = "Use Proxy";
variables.statusTexts[307] = "Temporary Redirect";
variables.statusTexts[308] = "Permanent Redirect";
variables.statusTexts[400] = "Bad Request";
variables.statusTexts[401] = "Unauthorized";
variables.statusTexts[402] = "Payment Required";
variables.statusTexts[403] = "Forbidden";
variables.statusTexts[404] = "Not Found";
variables.statusTexts[405] = "Method Not Allowed";
variables.statusTexts[406] = "Not Acceptable";
variables.statusTexts[407] = "Proxy Authentication Required";
variables.statusTexts[408] = "Request Timeout";
variables.statusTexts[409] = "Conflict";
variables.statusTexts[410] = "Gone";
variables.statusTexts[411] = "Length Required";
variables.statusTexts[412] = "Precondition Failed";
variables.statusTexts[413] = "Payload Too Large";
variables.statusTexts[414] = "Request-URI Too Long";
variables.statusTexts[415] = "Unsupported Media Type";
variables.statusTexts[416] = "Requested Range Not Satisfiable";
variables.statusTexts[417] = "Expectation Failed";
variables.statusTexts[418] = "I'm a teapot";
variables.statusTexts[421] = "Misdirected Request";
variables.statusTexts[422] = "Unprocessable Entity";
variables.statusTexts[423] = "Locked";
variables.statusTexts[424] = "Failed Dependency";
variables.statusTexts[426] = "Upgrade Required";
variables.statusTexts[428] = "Precondition Required";
variables.statusTexts[429] = "Too Many Requests";
variables.statusTexts[431] = "Request Header Fields Too Large";
variables.statusTexts[444] = "Connection Closed Without Response";
variables.statusTexts[451] = "Unavailable For Legal Reasons";
variables.statusTexts[499] = "Client Closed Request";
variables.statusTexts[500] = "Internal Server Error";
variables.statusTexts[501] = "Not Implemented";
variables.statusTexts[502] = "Bad Gateway";
variables.statusTexts[503] = "Service Unavailable";
variables.statusTexts[504] = "Gateway Timeout";
variables.statusTexts[505] = "HTTP Version Not Supported";
variables.statusTexts[506] = "Variant Also Negotiates";
variables.statusTexts[507] = "Insufficient Storage";
variables.statusTexts[508] = "Loop Detected";
variables.statusTexts[510] = "Not Extended";
variables.statusTexts[511] = "Network Authentication Required";
variables.statusTexts[599] = "Network Connect Timeout Error";
<cffunction name="getType" acces="public" output="false">
<cfreturn variables.types[variables.type] />
</cffunction>
public function getType() output="false" {
return variables.types[variables.type];
}
<cffunction name="setData" access="public" output="false" hint="setter for the data to be returned">
<cfargument name="data" required="true" hint="the simple or complex data that you want to return to the api consumer" />
<cfset variables.type = 1 />
<cfset variables.data = arguments.data />
<cfreturn this />
</cffunction>
public function setData(required data) output="false" hint="setter for the data to be returned" {
variables.type = 1;
variables.data = arguments.data;
return this;
}
<cffunction name="getData" access="public" output="false" hint="mostly for testability, returns the native data embedded in the representation instance">
<cfreturn variables.data />
</cffunction>
public function getData() output="false" hint="mostly for testability, returns the native data embedded in the representation instance" {
return variables.data;
}
<cffunction name="noData" access="public" output="false" hint="returns empty representation instance">
<cfif application._taffy.settings.noDataSends204NoContent>
<cfreturn this.noContent() />
<cfelse>
<cfreturn this />
</cfif>
</cffunction>
public function setNoDataSends204NoContent(required boolean value) output="false" {
variables.noDataSends204NoContent = arguments.value;
return this;
}
<cffunction name="noContent" access="public" output="false" hint="returns empty representation instance">
<!--- According to issue #365 https://github.com/atuttle/Taffy/issues/365
noContent() returns with HTTP status code 204 and Content-Type as text/plain (omitting this header is difficult and maybe not recommanded)
noData() is kept 'as is' for backward compatibility with existing implementations
--->
<cfreturn this.withStatus(204).withHeaders({"Content-Type"="text/plain"}) />
</cffunction>
public function noData() output="false" hint="returns empty representation instance" {
if (variables.noDataSends204NoContent) {
return this.noContent();
} else {
return this;
}
}
<cffunction name="setFileName" access="public" output="false" hint="Pass in a file-name (fully qualified, e.g. c:\temp\img.jpg) to have Taffy stream this file back to the client">
<cfargument name="file" type="string" required="true" />
<cfset variables.type = 2 />
<cfset variables.fileName = arguments.file />
<cfreturn this />
</cffunction>
public function noContent() output="false" hint="returns empty representation instance" {
// According to issue #365 https://github.com/atuttle/Taffy/issues/365
// noContent() returns with HTTP status code 204 and Content-Type as text/plain (omitting this header is difficult and maybe not recommanded)
// noData() is kept 'as is' for backward compatibility with existing implementations
return this.withStatus(204).withHeaders({"Content-Type"="text/plain"});
}
<cffunction name="getFileName" access="public" output="false">
<cfreturn variables.fileName />
</cffunction>
public function setFileName(required string file) output="false" hint="Pass in a file-name (fully qualified, e.g. c:\temp\img.jpg) to have Taffy stream this file back to the client" {
variables.type = 2;
variables.fileName = arguments.file;
return this;
}
<cffunction name="setFileData" access="public" output="false" hint="Pass in file data (eg a generated PDF object) - NOT a Filename! - to have Taffy stream the content back to the client">
<cfargument name="data" required="true" />
<cfset variables.type = 3 />
<cfset variables.fileData = arguments.data />
<cfreturn this />
</cffunction>
public function getFileName() output="false" {
return variables.fileName;
}
<cffunction name="getFileData" access="public" output="false">
<cfreturn variables.fileData />
</cffunction>
public function setFileData(required data) output="false" hint="Pass in file data (eg a generated PDF object) - NOT a Filename! - to have Taffy stream the content back to the client" {
variables.type = 3;
variables.fileData = arguments.data;
return this;
}
<cffunction name="setImageData" access="public" output="false" hint="Pass in image data (eg a generated image object) - NOT a Filename! - to have Taffy stream the content back to the client">
<cfargument name="data" required="true" />
<cfset variables.type = 4 />
<cfif not isBinary(arguments.data)>
<cfset arguments.data = toBinary(toBase64(arguments.data)) />
</cfif>
<cfset variables.fileData = arguments.data />
<cfreturn this />
</cffunction>
public function getFileData() output="false" {
return variables.fileData;
}
<cffunction name="getImageData" access="public" output="false">
<cfreturn getFileData() />
</cffunction>
public function setImageData(required data) output="false" hint="Pass in image data (eg a generated image object) - NOT a Filename! - to have Taffy stream the content back to the client" {
variables.type = 4;
if (!isBinary(arguments.data)) {
arguments.data = toBinary(toBase64(arguments.data));
}
variables.fileData = arguments.data;
return this;
}
<cffunction name="withMime" access="public" output="false" hint="Use this method in conjunction with streamFile and streamBinary in your resources to set the mime type of the file being returned. Ex: return streamFile('kittens/cuteness.jpg').withMime('image/jpeg');">
<cfargument name="mime" type="string" required="true" />
<cfset variables.fileMime = arguments.mime />
<cfreturn this />
</cffunction>
public function getImageData() output="false" {
return getFileData();
}
<cffunction name="getFileMime" access="public" output="false">
<cfreturn variables.fileMime />
</cffunction>
public function withMime(required string mime) output="false" hint="Use this method in conjunction with streamFile and streamBinary in your resources to set the mime type of the file being returned. Ex: return streamFile('kittens/cuteness.jpg').withMime('image/jpeg');" {
variables.fileMime = arguments.mime;
return this;
}
<cffunction name="withStatus" access="public" output="false" hint="used to set the http response code for the response">
<cfargument name="statusCode" type="numeric" required="true" hint="eg 200" />
<cfargument name="statusText" type="string" required="false" default="" />
<cfset variables.statusCode = arguments.statusCode />
<cfif len(arguments.statusText)>
<cfset variables.statusText = arguments.statusText />
<cfelseif StructKeyExists(variables.statusTexts, arguments.statusCode)>
<cfset variables.statusText = variables.statusTexts[arguments.statusCode] />
</cfif>
<cfreturn this />
</cffunction>
public function getFileMime() output="false" {
return variables.fileMime;
}
<cffunction name="getStatus" access="public" output="false" returnType="numeric">
<cfreturn variables.statusCode />
</cffunction>
public function withStatus(required numeric statusCode, string statusText="") output="false" hint="used to set the http response code for the response" {
variables.statusCode = arguments.statusCode;
if (len(arguments.statusText)) {
variables.statusText = arguments.statusText;
} else if (structKeyExists(variables.statusTexts, arguments.statusCode)) {
variables.statusText = variables.statusTexts[arguments.statusCode];
}
return this;
}
<cffunction name="getStatusText" access="public" output="false" returnType="string">
<cfreturn variables.statusText />
</cffunction>
public numeric function getStatus() output="false" {
return variables.statusCode;
}
<cffunction name="withHeaders" access="public" output="false" hint="used to set custom headers for the response">
<cfargument name="headerStruct" type="struct" required="true" />
<cfset variables.miscHeaders = arguments.headerStruct />
<cfreturn this />
</cffunction>
public string function getStatusText() output="false" {
return variables.statusText;
}
<cffunction name="getHeaders" access="public" output="false" returntype="Struct">
<cfreturn variables.miscHeaders />
</cffunction>
public function withHeaders(required struct headerStruct) output="false" hint="used to set custom headers for the response" {
variables.miscHeaders = arguments.headerStruct;
return this;
}
<cffunction name="andDelete" access="public" output="false" hint="used to delete the streamed file">
<cfargument name="doDeleteFile" type="boolean" required="true" />
<cfset variables.deleteFile = arguments.doDeleteFile />
<cfreturn this />
</cffunction>
public struct function getHeaders() output="false" {
return variables.miscHeaders;
}
<cffunction name="getDeleteFile" access="public" output="false" returntype="boolean">
<cfreturn variables.deleteFile />
</cffunction>
public function andDelete(required boolean doDeleteFile) output="false" hint="used to delete the streamed file" {
variables.deleteFile = arguments.doDeleteFile;
return this;
}
</cfcomponent>
public boolean function getDeleteFile() output="false" {
return variables.deleteFile;
}
}
+166 -174
View File
@@ -1,159 +1,138 @@
<cfcomponent output="false">
<cfscript>
//bean cache
this.beans = structNew();
this.transients = structNew();
//functionality
</cfscript>
component output="false" {
<cffunction name="init" output="false">
<cfargument name="externalBeanFactory">
<cfscript>
if (structKeyExists(arguments, "externalBeanFactory")) {
this.externalBeanFactory = arguments.externalBeanFactory;
}
return this;
</cfscript>
</cffunction>
// bean cache
this.beans = {};
this.transients = {};
<cfscript>
// Proxy to beanExists to provide similar interface to ColdSpring
function containsBean(beanName){
return beanExists(arguments.beanName);
public function init(externalBeanFactory) {
if (structKeyExists(arguments, "externalBeanFactory")) {
this.externalBeanFactory = arguments.externalBeanFactory;
}
function transientExists(beanName){
return structKeyExists(this.transients, arguments.beanName);
return this;
}
// Proxy to beanExists to provide similar interface to ColdSpring
public function containsBean(beanName) {
return beanExists(arguments.beanName);
}
public function transientExists(beanName) {
return structKeyExists(this.transients, arguments.beanName);
}
public function getBean(beanName) {
var b = 0;
var meta = 0;
if (beanExists(arguments.beanName, false, false)) {
return this.beans[arguments.beanName];
} else if (transientExists(arguments.beanName)) {
b = createObject('component', this.transients[arguments.beanName]);
meta = getMetadata(b);
_recurse_ResolveDependencies(b, meta);
return b;
} else if (externalBeanExists(arguments.beanName)) {
return this.externalBeanFactory.getBean(arguments.beanName);
} else {
throwError(message="Bean name '#arguments.beanName#' not found.", type="Taffy.Factory.BeanNotFound");
}
function getBean(beanName){
var b = 0;
var meta = 0;
if (beanExists(arguments.beanName, false, false)){
return this.beans[arguments.beanName];
}else if (transientExists(arguments.beanName)){
b = createObject('component', this.transients[arguments.beanName]);
meta = getMetadata(b);
_recurse_ResolveDependencies(b, meta);
return b;
}else if (externalBeanExists(arguments.beanName)){
return this.externalBeanFactory.getBean(arguments.beanName);
}else{
throwError(message="Bean name '#arguments.beanName#' not found.", type="Taffy.Factory.BeanNotFound");
}
public function getBeanList() {
var combined = structKeyList(this.beans);
var trans = structKeyList(this.transients);
if (len(combined) and len(trans)) {
combined = combined & ",";
}
combined = combined & trans;
return combined;
}
public function beanExists(required beanName, includeTransients=true, includeExternal=false) output="false" {
return structKeyExists(this.beans, arguments.beanName) or (arguments.includeTransients and transientExists(arguments.beanName)) or
(arguments.includeExternal and externalBeanExists(arguments.beanName));
}
private boolean function externalBeanExists(required beanName) output="false" {
return structKeyExists(this, "externalBeanFactory") and this.externalBeanFactory.containsBean(arguments.beanName);
}
public void function loadBeansFromPath(
required string beanPath hint="Absolute path to folder containing beans",
string resourcesPath="resources",
string resourcesBasePath="",
boolean isFullReload=false,
taffyRef={}
) output="false" {
var local = {};
// cache all of the beans
if (isFullReload) {
this.beans = {};
arguments.taffyRef.status.skippedResources = []; // empty out the array on factory reloads
arguments.taffyRef.beanList = "";
}
// if the folder doesn't exist, do nothing
if (!directoryExists(arguments.beanPath)) {
return;
}
// get list of beans to load
local.beanQuery = directoryList(arguments.beanPath, true, "query", "*.cfc");
for (var row in local.beanQuery) {
local.beanName = filePathToBeanName(row.directory, row.name, arguments.resourcesBasePath);
local.beanPath = filePathToBeanPath(row.directory, row.name, arguments.resourcesPath, arguments.resourcesBasePath);
try {
local.objBean = createObject("component", local.beanPath);
if (isSerializerInstance(local.objBean)) {
this.transients[local.beanName] = local.beanPath;
} else {
this.beans[local.beanName] = local.objBean;
}
} catch (any e) {
// skip cfc's with errors, but save info about them for display in the dashboard
local.err = {};
local.err.resource = local.beanName;
local.err.exception = e;
arrayAppend(arguments.taffyRef.status.skippedResources, local.err);
}
}
function getBeanList(){
var combined = structKeyList(this.beans);
var trans = structKeyList(this.transients);
if (len(combined) and len(trans)){
combined = combined & ",";
}
combined = combined & trans;
return combined;
// resolve dependencies
for (local.b in this.beans) {
local.bean = this.beans[local.b];
local.beanMeta = getMetadata(local.bean);
_recurse_ResolveDependencies(local.bean, local.beanMeta);
}
</cfscript>
<cffunction name="beanExists" output="false">
<cfargument required="true" name="beanName">
<cfargument name="includeTransients" default="true">
<cfargument name="includeExternal" default="false">
<cfscript>
return structKeyExists(this.beans, arguments.beanName) or (arguments.includeTransients and transientExists(arguments.beanName)) or
(arguments.includeExternal and externalBeanExists(arguments.beanName));
</cfscript>
</cffunction>
<cffunction name="externalBeanExists" access="private" output="false" returnType="boolean">
<cfargument required="true" name="beanName">
<cfscript>
return structKeyExists(this, "externalBeanFactory") and this.externalBeanFactory.containsBean(arguments.beanName);
</cfscript>
</cffunction>
<cffunction name="loadBeansFromPath" access="public" output="false" returnType="void">
<cfargument name="beanPath" type="string" required="true" hint="Absolute path to folder containing beans" />
<cfargument name="resourcesPath" type="string" default="resources" />
<cfargument name="resourcesBasePath" type="string" default="" />
<cfargument name="isFullReload" type="boolean" default="false" />
<cfargument name="taffyRef" type="any" required="false" default="#structNew()#" />
<cfset var local = StructNew() />
<!--- cache all of the beans --->
<cfif isFullReload>
<cfset this.beans = structNew() />
<cfset arguments.taffyRef.status.skippedResources = arrayNew(1) /> <!--- empty out the array on factory reloads --->
<cfset arguments.taffyRef.beanList = "" />
</cfif>
<!--- if the folder doesn't exist, do nothing --->
<cfif not directoryExists(arguments.beanPath)>
<cfreturn />
</cfif>
<!--- get list of beans to load --->
<cfdirectory action="list" directory="#arguments.beanPath#" filter="*.cfc" name="local.beanQuery" recurse="true" />
<cfloop query="local.beanQuery">
<cfset local.beanName = filePathToBeanName(local.beanQuery.directory, local.beanquery.name, arguments.resourcesBasePath) />
<cfset local.beanPath = filePathToBeanPath(local.beanQuery.directory, local.beanquery.name, arguments.resourcesPath, arguments.resourcesBasePath) />
<cftry>
<cfset local.objBean = createObject("component", local.beanPath) />
<cfif isInstanceOf(local.objBean, "taffy.core.baseSerializer")>
<cfset this.transients[local.beanName] = local.beanPath />
<cfelse>
<cfset this.beans[local.beanName] = local.objBean />
</cfif>
<cfcatch>
<!--- skip cfc's with errors, but save info about them for display in the dashboard --->
<cfset local.err = structNew() />
<cfset local.err.resource = local.beanName />
<cfset local.err.exception = cfcatch />
<cfset arrayAppend(arguments.taffyRef.status.skippedResources, local.err) />
</cfcatch>
</cftry>
</cfloop>
<!--- resolve dependencies --->
<cfloop list="#structKeyList(this.beans)#" index="local.b">
<cfset local.bean = this.beans[local.b] />
<cfset local.beanMeta = getMetadata(local.bean) />
<cfset _recurse_ResolveDependencies(local.bean, local.beanMeta) />
</cfloop>
</cffunction>
}
<cffunction name="filePathToBeanPath" access="private">
<cfargument name="path" />
<cfargument name="filename" />
<cfargument name="resourcesPath" />
<cfargument name="resourcesBasePath" />
<cfset var beanPath = "" />
<cfif len(resourcesBasePath) eq 0>
<cfset arguments.resourcesBasePath = "!@$%^&*()" />
</cfif>
<cfset beanPath =
private function filePathToBeanPath(path, filename, resourcesPath, resourcesBasePath) {
var beanPath = "";
if (len(resourcesBasePath) eq 0) {
arguments.resourcesBasePath = "!@$%^&*()";
}
beanPath =
resourcesPath
&
"."
&
replaceList(
& "."
& replaceList(
replace(path, resourcesBasePath, ""),
"/,\",
".,."
)
&
"."
&
replace(
& "."
& replace(
filename,
".cfc",
""
)
/>
<cfset beanPath = replace(beanPath, "..", ".", "ALL") />
<cfif left(beanPath, 1) eq ".">
<cfset beanPath = right(beanPath, len(beanPath)-1) />
</cfif>
<cfreturn beanPath />
</cffunction>
);
beanPath = replace(beanPath, "..", ".", "ALL");
if (left(beanPath, 1) eq ".") {
beanPath = right(beanPath, len(beanPath)-1);
}
return beanPath;
}
<cffunction name="filePathToBeanName" access="private">
<cfargument name="path" />
<cfargument name="filename" />
<cfargument name="basepath" />
<cfif len(basepath) eq 0>
<cfset arguments.basePath = "!@$%^&*()" />
</cfif>
<cfreturn
private function filePathToBeanName(path, filename, basepath) {
if (len(basepath) eq 0) {
arguments.basePath = "!@$%^&*()";
}
return
replaceList(
replace(path, basepath, ""),
"/,\",
@@ -163,40 +142,53 @@
filename,
".cfc",
""
)
/>
</cffunction>
);
}
<cffunction name="_recurse_ResolveDependencies" access="private">
<cfargument name="bean" required="true" />
<cfargument name="metaData" type="struct" required="true" />
<cfset var local = structNew() />
<cfif structKeyExists(arguments.metaData, "functions") and isArray(arguments.metaData.functions)>
<cfloop from="1" to="#arrayLen(arguments.metaData.functions)#" index="local.f">
<cfset local.fname = arguments.metaData.functions[local.f].name />
<cfif len(local.fname) gt 3>
<cfset local.propName = right(local.fname, len(local.fname)-3) />
<cfif left(local.fname, 3) eq "set" and beanExists(local.propName, true, true)>
<cfset evaluate("arguments.bean.#local.fname#(getBean('#local.propName#'))") />
</cfif>
</cfif>
</cfloop>
</cfif>
<cfif structKeyExists(arguments.metaData, "properties") and isArray(arguments.metaData.properties)>
<cfloop from="1" to="#arrayLen(arguments.metaData.properties)#" index="local.p">
<cfset local.propName = arguments.metaData.properties[local.p].name />
<cfif beanExists(local.propName, true, true)>
<cfset arguments.bean[local.propName] = getBean(local.propName) />
</cfif>
</cfloop>
</cfif>
<cfif structKeyExists(arguments.metaData, "extends") and isStruct(arguments.metaData.extends)>
<cfset _recurse_ResolveDependencies(arguments.bean, arguments.metaData.extends) />
</cfif>
</cffunction>
<!--- proxy function for CF8 compatibility --->
<cffunction name="throwError">
<cfthrow attributecollection="#arguments#" />
</cffunction>
private function _recurse_ResolveDependencies(required bean, required struct metaData) {
var local = {};
if (structKeyExists(arguments.metaData, "functions") and isArray(arguments.metaData.functions)) {
for (local.f = 1; local.f <= arrayLen(arguments.metaData.functions); local.f++) {
local.fname = arguments.metaData.functions[local.f].name;
if (len(local.fname) gt 3) {
local.propName = right(local.fname, len(local.fname)-3);
if (left(local.fname, 3) eq "set" and beanExists(local.propName, true, true)) {
invoke(arguments.bean, local.fname, [getBean(local.propName)]);
}
}
}
}
if (structKeyExists(arguments.metaData, "properties") and isArray(arguments.metaData.properties)) {
for (local.p = 1; local.p <= arrayLen(arguments.metaData.properties); local.p++) {
local.propName = arguments.metaData.properties[local.p].name;
if (beanExists(local.propName, true, true)) {
arguments.bean[local.propName] = getBean(local.propName);
}
}
}
if (structKeyExists(arguments.metaData, "extends") and isStruct(arguments.metaData.extends)) {
_recurse_ResolveDependencies(arguments.bean, arguments.metaData.extends);
}
}
</cfcomponent>
/**
* Walks the inheritance chain to check if obj extends baseSerializer.
* Replaces isInstanceOf() which fails on Lucee when extends resolves
* to a relative path instead of a mapping-prefixed path.
*/
private boolean function isSerializerInstance(required any obj) output="false" {
if (!isObject(arguments.obj)) return false;
var meta = getMetadata(arguments.obj);
while (structKeyExists(meta, "name")) {
if (listLast(meta.name, ".") == "baseSerializer") return true;
if (!structKeyExists(meta, "extends")) break;
meta = meta.extends;
}
return false;
}
private function throwError() {
cfthrow(attributecollection=arguments);
}
}
+16 -17
View File
@@ -1,21 +1,20 @@
<cfcomponent extends="taffy.core.baseDeserializer">
component extends="baseDeserializer" {
<cffunction name="getFromJson" output="false" taffy:mime="application/json,text/json" hint="get data from json">
<cfargument name="body" hint="the textual request body" />
<cfset var data = 0 />
<cfset var response = {} />
public function getFromJson(body) output="false" taffy_mime="application/json,text/json" hint="get data from json" {
var data = 0;
var response = {};
<cfif not isJson(arguments.body)>
<cfset throwError(msg="Input JSON is not well formed", statusCode="400") />
</cfif>
<cfset data = deserializeJSON(arguments.body) />
<cfif not isStruct(data)>
<cfset response['_body'] = data />
<cfelse>
<cfset response = data />
</cfif>
if (!isJson(arguments.body)) {
throwError(msg="Input JSON is not well formed", statusCode="400");
}
data = deserializeJSON(arguments.body);
if (!isStruct(data)) {
response['_body'] = data;
} else {
response = data;
}
<cfreturn response />
</cffunction>
return response;
}
</cfcomponent>
}
+5 -10
View File
@@ -1,12 +1,7 @@
<cfcomponent extends="taffy.core.baseSerializer" output="false" hint="Serializer that uses CFML server's json serialization functionality to return json data">
component extends="baseSerializer" output="false" hint="Serializer that uses CFML server's json serialization functionality to return json data" {
<cffunction
name="getAsJson"
output="false"
taffy:mime="application/json;text/json"
taffy:default="true"
hint="serializes data as JSON">
<cfreturn rereplace(replace(serializeJSON(variables.data), chr(2), '', 'ALL'), '"\\u0002', '"', 'ALL') />
</cffunction>
public function getAsJson() output="false" taffy_mime="application/json;text/json" taffy_default="true" hint="serializes data as JSON" {
return rereplace(replace(serializeJSON(variables.data), chr(2), '', 'ALL'), '"\\u0002', '"', 'ALL');
}
</cfcomponent>
}
+297
View File
@@ -0,0 +1,297 @@
component output="false" hint="Generates an OpenAPI 3.1 document from Taffy runtime metadata." {
public struct function generate()
hint="Returns an OpenAPI 3.1 struct describing all registered resources." {
var settings = application._taffy.settings;
var endpoints = application._taffy.endpoints;
var matchOrder = application._taffy.uriMatchOrder;
var openapiCfg = structKeyExists(settings, "openapi") ? settings.openapi : {};
var mediaTypes = collectResponseMediaTypes();
var doc = {
"openapi": "3.1.0",
"info": buildInfo(settings, openapiCfg),
"paths": {}
};
var servers = buildServers(openapiCfg);
if (arrayLen(servers)) {
doc["servers"] = servers;
}
for (var i = 1; i <= arrayLen(matchOrder); i++) {
var endpoint = endpoints[matchOrder[i]];
var bean = application._taffy.factory.getBean(endpoint.beanName);
var beanMeta = getMetaData(bean);
if (hasAnyKey(beanMeta, "taffy_docs_hide,taffy:docs:hide,taffy_dashboard_hide,taffy:dashboard:hide")) {
continue;
}
var funcs = collectFunctions(beanMeta);
var pathItem = {};
var validVerbs = "get,put,post,delete,options,head,patch,trace";
for (var verb in endpoint.methods) {
if (!listFindNoCase(validVerbs, verb)) continue;
var funcName = endpoint.methods[verb];
if (!structKeyExists(funcs, funcName)) continue;
var func = funcs[funcName];
if (hasAnyKey(func, "taffy_docs_hide,taffy:docs:hide,taffy_dashboard_hide,taffy:dashboard:hide")) continue;
pathItem[lcase(verb)] = buildOperation(verb, func, endpoint, beanMeta, mediaTypes);
}
if (!structIsEmpty(pathItem)) {
doc.paths[normalizePathTemplate(endpoint.srcUri, endpoint.tokens)] = pathItem;
}
}
return doc;
}
private struct function buildInfo(required struct settings, required struct openapiCfg) {
var info = {
"title": arguments.settings.docs.APIName,
"version": arguments.settings.docs.APIVersion
};
if (structKeyExists(arguments.openapiCfg, "description")) info["description"] = arguments.openapiCfg.description;
if (structKeyExists(arguments.openapiCfg, "contact")) info["contact"] = arguments.openapiCfg.contact;
if (structKeyExists(arguments.openapiCfg, "license")) info["license"] = arguments.openapiCfg.license;
return info;
}
private array function buildServers(required struct openapiCfg) {
if (structKeyExists(arguments.openapiCfg, "servers") && isArray(arguments.openapiCfg.servers)) {
return arguments.openapiCfg.servers;
}
var host = cgi.http_host;
if (!len(host)) return [];
var isHttps = cgi.server_port == 443 || (structKeyExists(cgi, "https") && cgi.https == "on");
var scheme = isHttps ? "https" : "http";
var scriptDir = getDirectoryFromPath(cgi.script_name);
if (right(scriptDir, 1) == "/" && len(scriptDir) > 1) {
scriptDir = left(scriptDir, len(scriptDir) - 1);
}
return [ { "url": scheme & "://" & host & scriptDir } ];
}
private array function collectResponseMediaTypes()
hint="Unique MIME type strings Taffy can return, derived from registered serializers." {
var mimes = {};
for (var ext in application._taffy.settings.mimeExtensions) {
for (var part in listToArray(application._taffy.settings.mimeExtensions[ext], ";")) {
mimes[trim(part)] = true;
}
}
var out = [];
for (var m in mimes) arrayAppend(out, m);
arraySort(out, "text");
return out;
}
private struct function collectFunctions(required struct metadata)
hint="Flatten the cfc's function metadata (including inherited) keyed by name. Child overrides parent." {
var result = {};
if (structKeyExists(arguments.metadata, "extends") && arguments.metadata.extends.fullname != "taffy.core.resource") {
result = collectFunctions(arguments.metadata.extends);
}
if (!structKeyExists(arguments.metadata, "functions") || !isArray(arguments.metadata.functions)) {
return result;
}
for (var f = 1; f <= arrayLen(arguments.metadata.functions); f++) {
var func = arguments.metadata.functions[f];
if (structKeyExists(func, "access") && (func.access == "private" || func.access == "package")) continue;
result[func.name] = func;
}
return result;
}
private struct function buildOperation(
required string verb,
required struct func,
required struct endpoint,
required struct beanMeta,
required array mediaTypes
) {
var op = {
"tags": [ getResourceTag(arguments.beanMeta, arguments.endpoint.beanName) ],
"operationId": arguments.endpoint.beanName & "_" & lcase(arguments.verb)
};
if (structKeyExists(arguments.beanMeta, "taffy:docs:name")) {
op["summary"] = arguments.beanMeta["taffy:docs:name"];
} else if (structKeyExists(arguments.beanMeta, "taffy_docs_name")) {
op["summary"] = arguments.beanMeta["taffy_docs_name"];
}
if (structKeyExists(arguments.func, "hint")) op["description"] = arguments.func.hint;
var tokenLookup = {};
for (var t = 1; t <= arrayLen(arguments.endpoint.tokens); t++) {
tokenLookup[lcase(arguments.endpoint.tokens[t])] = arguments.endpoint.tokens[t];
}
var parameters = [];
var bodyParams = [];
var declaredPathTokens = {};
var params = structKeyExists(arguments.func, "parameters") ? arguments.func.parameters : [];
var isBodyVerb = listFindNoCase("post,put,patch", arguments.verb) > 0;
for (var p = 1; p <= arrayLen(params); p++) {
var param = params[p];
if (hasAnyKey(param, "taffy_docs_hide,taffy:docs:hide,taffy_dashboard_hide,taffy:dashboard:hide")) continue;
if (structKeyExists(tokenLookup, lcase(param.name))) {
// use the token's original casing so the parameter name matches the path template exactly
arrayAppend(parameters, buildParameter(param, "path", true, tokenLookup[lcase(param.name)]));
declaredPathTokens[lcase(param.name)] = true;
} else if (isBodyVerb) {
arrayAppend(bodyParams, param);
} else {
var required = structKeyExists(param, "required") && param.required;
arrayAppend(parameters, buildParameter(param, "query", required));
}
}
// backfill any path tokens the resource didn't declare as args — OpenAPI requires a parameter for every {token}
for (var t2 = 1; t2 <= arrayLen(arguments.endpoint.tokens); t2++) {
var tok = arguments.endpoint.tokens[t2];
if (!structKeyExists(declaredPathTokens, lcase(tok))) {
arrayAppend(parameters, {
"name": tok,
"in": "path",
"required": true,
"schema": { "type": "string" }
});
}
}
if (arrayLen(parameters)) op["parameters"] = parameters;
if (isBodyVerb && arrayLen(bodyParams)) op["requestBody"] = buildRequestBody(bodyParams);
op["responses"] = buildResponses(arguments.mediaTypes);
return op;
}
private struct function buildParameter(required struct param, required string location, required boolean required, string nameOverride = "") {
var out = {
"name": len(arguments.nameOverride) ? arguments.nameOverride : arguments.param.name,
"in": arguments.location,
"required": arguments.required,
"schema": paramSchema(arguments.param)
};
if (structKeyExists(arguments.param, "hint")) out["description"] = arguments.param.hint;
return out;
}
private struct function buildRequestBody(required array bodyParams) {
var properties = {};
var required = [];
for (var p = 1; p <= arrayLen(arguments.bodyParams); p++) {
var param = arguments.bodyParams[p];
var schema = paramSchema(param);
if (structKeyExists(param, "hint")) schema["description"] = param.hint;
properties[param.name] = schema;
if (structKeyExists(param, "required") && param.required) arrayAppend(required, param.name);
}
var bodySchema = { "type": "object", "properties": properties };
if (arrayLen(required)) bodySchema["required"] = required;
return {
"content": {
"application/json": { "schema": bodySchema },
"application/x-www-form-urlencoded": { "schema": bodySchema }
}
};
}
private struct function buildResponses(required array mediaTypes) {
var content = {};
for (var i = 1; i <= arrayLen(arguments.mediaTypes); i++) {
content[arguments.mediaTypes[i]] = {};
}
var ok = { "description": "Successful response" };
if (!structIsEmpty(content)) ok["content"] = content;
return { "200": ok, "default": { "description": "Unexpected error" } };
}
private struct function paramSchema(required struct param) {
var schema = cfmlTypeToSchema(structKeyExists(arguments.param, "type") ? arguments.param.type : "");
if (structKeyExists(arguments.param, "default") && len(arguments.param.default)) {
schema["default"] = arguments.param.default;
}
return schema;
}
private struct function cfmlTypeToSchema(required string type) {
switch (lcase(trim(arguments.type))) {
case "numeric": case "number": case "double": case "float":
return { "type": "number" };
case "integer":
return { "type": "integer" };
case "string":
return { "type": "string" };
case "boolean":
return { "type": "boolean" };
case "struct":
return { "type": "object" };
case "array":
return { "type": "array" };
case "date": case "datetime":
return { "type": "string", "format": "date-time" };
case "uuid": case "guid":
return { "type": "string", "format": "uuid" };
case "email":
return { "type": "string", "format": "email" };
case "url":
return { "type": "string", "format": "uri" };
case "": case "any": case "variablename":
return {};
default:
return { "type": "string" };
}
}
private string function getResourceTag(required struct beanMeta, required string beanName) {
if (structKeyExists(arguments.beanMeta, "taffy:docs:name")) return arguments.beanMeta["taffy:docs:name"];
if (structKeyExists(arguments.beanMeta, "taffy_docs_name")) return arguments.beanMeta["taffy_docs_name"];
return arguments.beanName;
}
private string function normalizePathTemplate(required string uri, required array tokens)
hint="Rebuild Taffy's URI as an OpenAPI path template: {name:regex} => {name}. Handles nested braces in token regexes." {
var out = "";
var i = 1;
var tokenIdx = 1;
var n = len(arguments.uri);
while (i <= n) {
var ch = mid(arguments.uri, i, 1);
if (ch == "{") {
// find the matching close brace, honoring nesting
var depth = 1;
var j = i + 1;
while (j <= n && depth > 0) {
var c2 = mid(arguments.uri, j, 1);
if (c2 == "{") depth++;
else if (c2 == "}") depth--;
if (depth > 0) j++;
}
if (depth == 0 && tokenIdx <= arrayLen(arguments.tokens)) {
out &= "{" & arguments.tokens[tokenIdx] & "}";
tokenIdx++;
i = j + 1;
continue;
}
}
out &= ch;
i++;
}
return out;
}
private boolean function hasAnyKey(required struct target, required string keys) {
for (var k in listToArray(arguments.keys)) {
if (structKeyExists(arguments.target, k)) return true;
}
return false;
}
}
+121 -125
View File
@@ -1,141 +1,137 @@
<cfcomponent hint="base class for taffy REST components">
component hint="base class for taffy REST components" {
<cffunction name="forceString">
<cfargument name="data" required="true" hint="the data that is being forced to serialize as a string" />
<cfreturn chr(2) & arguments.data />
</cffunction>
public function forceString(required data) hint="the data that is being forced to serialize as a string" {
return chr(2) & arguments.data;
}
<cfset variables.encode = structNew() />
<cfset variables.encode.string = forceString />
variables.encode = {};
variables.encode.string = forceString;
<!--- helper functions --->
<cffunction name="representationOf" access="public" output="false" hint="returns an object capable of serializing the data in a variety of formats">
<cfargument name="data" required="true" hint="any simple or complex data that should be returned for the request" />
<cfreturn getRepInstance().setData(arguments.data) />
</cffunction>
public function representationOf(required data) output="false" hint="returns an object capable of serializing the data in a variety of formats" {
return getRepInstance().setData(arguments.data);
}
<cffunction name="rep" access="public" output="false" hint="alias for representationOf">
<cfargument name="data" required="true" />
<cfreturn representationOf(arguments.data) />
</cffunction>
public function rep(required data) output="false" hint="alias for representationOf" {
return representationOf(arguments.data);
}
<cffunction name="noData" access="private" output="false" hint="use this function to return only headers to the consumer, no data">
<cfreturn getRepInstance().noData() />
</cffunction>
private function noData() output="false" hint="use this function to return only headers to the consumer, no data" {
return getRepInstance().noData();
}
<cffunction name="noContent" access="private" output="false" hint="use this function to return only headers to the consumer, no data">
<cfreturn getRepInstance().noContent() />
</cffunction>
private function noContent() output="false" hint="use this function to return only headers to the consumer, no data" {
return getRepInstance().noContent();
}
<cffunction name="streamFile" access="private" output="false" hint="Use this function to specify a file name (eg c:\tmp\kitten.jpg) to be streamed to the client. When you use this method it is *required* that you also use .withMime() to specify the mime type.">
<cfargument name="fileName" required="true" hint="fully qualified file path (eg c:\tmp\kitten.jpg)" />
<cfreturn getRepInstance().setFileName(arguments.fileName) />
</cffunction>
private function streamFile(required fileName) output="false" hint="Use this function to specify a file name (eg c:\tmp\kitten.jpg) to be streamed to the client. When you use this method it is *required* that you also use .withMime() to specify the mime type." {
return getRepInstance().setFileName(arguments.fileName);
}
<cffunction name="streamBinary" access="private" output="false" hint="Use this function to stream binary data, like a generated PDF object, to the client. When you use this method it is *required* that you also use .withMime() to specify the mime type.">
<cfargument name="binaryData" required="true" hint="binary file data (eg a PDF object) that you want to return to the client" />
<cfreturn getRepInstance().setFileData(arguments.binaryData) />
</cffunction>
private function streamBinary(required binaryData) output="false" hint="Use this function to stream binary data, like a generated PDF object, to the client. When you use this method it is *required* that you also use .withMime() to specify the mime type." {
return getRepInstance().setFileData(arguments.binaryData);
}
<cffunction name="streamImage" access="private" output="false" hint="Use this function to stream binary data, like a generated PDF object, to the client. When you use this method it is *required* that you also use .withMime() to specify the mime type.">
<cfargument name="binaryData" required="true" hint="binary file data (eg a PDF object or image data) that you want to return to the client" />
<cfreturn getRepInstance().setImageData(arguments.binaryData) />
</cffunction>
private function streamImage(required binaryData) output="false" hint="Use this function to stream binary data, like a generated PDF object, to the client. When you use this method it is *required* that you also use .withMime() to specify the mime type." {
return getRepInstance().setImageData(arguments.binaryData);
}
<cffunction name="saveLog">
<cfargument name="exception" />
<cfset logger = createObject("component", application._taffy.settings.exceptionLogAdapter).init(
application._taffy.settings.exceptionLogAdapterConfig
) />
<cfset logger.saveLog(exception) />
</cffunction>
public function saveLog(exception) {
var logger = createObject("component", application._taffy.settings.exceptionLogAdapter).init(
application._taffy.settings.exceptionLogAdapterConfig
);
logger.saveLog(exception);
}
<cffunction name="queryToArray" access="private" returntype="array" output="false">
<cfargument name="q" type="query" required="yes" />
<cfargument name="cb" type="any" required="no" />
<cfscript>
var local = {};
if (structKeyExists(server, "railo") or structKeyExists(server, "lucee")) {
local.Columns = listToArray(arguments.q.getColumnList(false));
}
else {
local.Columns = arguments.q.getMetaData().getColumnLabels();
}
local.QueryArray = ArrayNew(1);
for (local.RowIndex = 1; local.RowIndex <= arguments.q.RecordCount; local.RowIndex++){
local.Row = {};
local.numCols = ArrayLen( local.Columns );
for (local.ColumnIndex = 1; local.ColumnIndex <= local.numCols; local.ColumnIndex++){
local.ColumnName = local.Columns[ local.ColumnIndex ];
if( local.ColumnName NEQ "" ) {
local.Row[ local.ColumnName ] = arguments.q[ local.ColumnName ][ local.RowIndex ];
}
}
if ( structKeyExists( arguments, "cb" ) ) {
local.Row = cb( local.Row );
}
ArrayAppend( local.QueryArray, local.Row );
}
return( local.QueryArray );
</cfscript>
</cffunction>
<cffunction name="queryToStruct" access="private" returntype="struct" output="false">
<cfargument name="q" type="query" required="yes" />
<cfargument name="cb" type="any" required="no" />
<cfset var local = {} />
<cfif q.recordcount gt 1>
<cfthrow message="Unable to convert query resultset with more than one record to a simple struct, use queryToArray() instead" />
</cfif>
<cfscript>
if (structKeyExists(server, "railo") or structKeyExists(server, "lucee")) {
local.Columns = listToArray(arguments.q.getColumnList(false));
}
else {
local.Columns = arguments.q.getMetaData().getColumnLabels();
}
local.QueryStruct = {};
local.numCols = ArrayLen( local.Columns );
for (local.ColumnIndex = 1; local.ColumnIndex <= local.numCols; local.ColumnIndex++){
local.ColumnName = local.Columns[ local.ColumnIndex ];
if( local.ColumnName NEQ "" ) {
if ( structKeyExists( arguments, "cb" ) ) {
local.QueryStruct[ local.ColumnName ] = cb( local.ColumnName, arguments.q[ local.ColumnName ][1] );
} else {
local.QueryStruct[ local.ColumnName ] = arguments.q[ local.ColumnName ][1];
}
private array function qToArray(required query q, cb) output="false" {
var local = {};
if (structKeyExists(server, "lucee")) {
local.Columns = listToArray(arguments.q.getColumnList(false));
} else {
local.Columns = arguments.q.getMetaData().getColumnLabels();
}
local.QueryArray = [];
for (local.RowIndex = 1; local.RowIndex <= arguments.q.RecordCount; local.RowIndex++) {
local.Row = {};
local.numCols = arrayLen(local.Columns);
for (local.ColumnIndex = 1; local.ColumnIndex <= local.numCols; local.ColumnIndex++) {
local.ColumnName = local.Columns[local.ColumnIndex];
if (local.ColumnName != "") {
local.Row[local.ColumnName] = arguments.q[local.ColumnName][local.RowIndex];
}
}
if (structKeyExists(arguments, "cb")) {
local.Row = cb(local.Row);
}
arrayAppend(local.QueryArray, local.Row);
}
return local.QueryArray;
}
return( local.QueryStruct );
</cfscript>
</cffunction>
variables.funcs = getFunctionList();
if (!structKeyExists(variables.funcs, "queryToArray")) {
private array function queryToArray(required query q, cb) output="false" {
return qToArray(arguments.q, arguments.cb);
}
}
<!---
function that gets the representation class instance
-- if the argument is blank, we use the default from taffy settings
-- if the argument is a beanName, the bean is returned from the factory;
-- otherwise it is assumed to be a cfc path and that cfc instance is returned
--->
<cffunction name="getRepInstance" access="private" output="false">
<cfargument name="repClass" type="string" default="" />
<cfif repClass eq "">
<!--- recursion not the most efficient path here, but it's damn readable --->
<cfreturn getRepInstance(application._taffy.settings.serializer) />
<cfelseif application._taffy.factory.containsBean(arguments.repClass)>
<cfreturn application._taffy.factory.getBean(arguments.repClass) />
<cfelse>
<cfreturn createObject("component", arguments.repClass) />
</cfif>
</cffunction>
<cffunction name="addDebugData" access="package" output="false">
<cfargument name="data" type="any" />
<cfset request.debugData = arguments.data />
</cffunction>
private struct function qToStruct(required query q, cb) output="false" {
var local = {};
</cfcomponent>
if (q.recordcount gt 1) {
throw(message="Unable to convert query resultset with more than one record to a simple struct, use queryToArray() instead");
}
if (structKeyExists(server, "lucee")) {
local.Columns = listToArray(arguments.q.getColumnList(false));
} else {
local.Columns = arguments.q.getMetaData().getColumnLabels();
}
local.QueryStruct = {};
local.numCols = arrayLen(local.Columns);
for (local.ColumnIndex = 1; local.ColumnIndex <= local.numCols; local.ColumnIndex++) {
local.ColumnName = local.Columns[local.ColumnIndex];
if (local.ColumnName != "") {
if (structKeyExists(arguments, "cb")) {
local.QueryStruct[local.ColumnName] = cb(local.ColumnName, arguments.q[local.ColumnName][1]);
} else {
local.QueryStruct[local.ColumnName] = arguments.q[local.ColumnName][1];
}
}
}
return local.QueryStruct;
}
if (!structKeyExists(variables.funcs, "queryToStruct")) {
private struct function queryToStruct(required query q, cb) output="false" {
return qToStruct(arguments.q, arguments.cb);
}
}
/**
* function that gets the representation class instance
* -- if the argument is blank, we use the default from taffy settings
* -- if the argument is a beanName, the bean is returned from the factory;
* -- otherwise it is assumed to be a cfc path and that cfc instance is returned
*/
private function getRepInstance(string repClass="") output="false" {
var rep = "";
if (repClass eq "") {
// recursion not the most efficient path here, but it's damn readable
return getRepInstance(application._taffy.settings.serializer);
} else if (application._taffy.factory.containsBean(arguments.repClass)) {
rep = application._taffy.factory.getBean(arguments.repClass);
} else {
rep = createObject("component", arguments.repClass);
}
rep.setNoDataSends204NoContent(application._taffy.settings.noDataSends204NoContent);
return rep;
}
package function addDebugData(data) output="false" {
request.debugData = arguments.data;
}
}