Skip to content

Instantly share code, notes, and snippets.

@Zoramite
Created February 3, 2011 06:58
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 Zoramite/809143 to your computer and use it in GitHub Desktop.
Save Zoramite/809143 to your computer and use it in GitHub Desktop.
Railo multiple variables scope bug
<cfcomponent output="false">
<cfscript>
public component function init() {
variables.columns = [];
variables.extend = createObject('component', 'extend').init();
return this;
}
public void function addColumn(struct options = {}) {
var defaults = {
class = '',
format = '',
key = '',
label = '',
link = [],
title = '',
type = 'text',
value = ''
};
// Normalize the options
if (structKeyExists(arguments.options, 'link') && !isArray(arguments.options.link)) {
arguments.options.link = [ arguments.options.link ];
}
arrayAppend(variables.columns, variables.extend.extend(defaults, arguments.options));
}
</cfscript>
<cffunction name="createLink" access="private" returntype="string" output="false">
<cfargument name="text" type="any" required="true" />
<cfargument name="column" type="struct" required="true" />
<cfargument name="data" type="any" required="true" />
<cfargument name="rowNum" type="numeric" required="true" />
<cfargument name="colNum" type="numeric" required="true" />
<cfargument name="options" type="struct" default="#{}#" />
<cfset var href = '' />
<cfset var html = '' />
<cfset var i = '' />
<cfset var j = '' />
<cfset var theUrl = '' />
<cfset var value = '' />
<cfset theUrl = arguments.options.theUrl />
<!--- Adjust for the startRow --->
<cfset arguments.rowNum += arguments.options.startRow - 1 />
<cfsavecontent variable="html">
<cfoutput>
<cfloop from="1" to="#arrayLen(arguments.column.link)#" index="i">
<cfloop list="#structKeyList(arguments.column.link[i])#" index="j">
<cfset value = arguments.data[arguments.rowNum][arguments.column.link[i][j]] />
<cfset theUrl['setDGCol#arguments.colNum#Link#i#'](j, value) />
</cfloop>
<cfset href = theUrl['getDGCol#arguments.colNum#Link#i#']() />
<a href="#href#">#arguments.text#</a>
</cfloop>
</cfoutput>
</cfsavecontent>
<cfreturn html />
</cffunction>
<cffunction name="toHTML" access="public" returntype="string" output="false">
<cfargument name="data" type="any" required="true" />
<cfargument name="options" type="struct" default="#{}#" />
<cfset var col = '' />
<cfset var counter = '' />
<cfset var defaults = {
class = '',
linkBase = '',
minimumRows = 15,
numPerPage = 30,
startRow = 1
} />
<cfset var html = '' />
<cfset var i = '' />
<cfset var item = '' />
<cfset var rowNum = '' />
<cfset var title = '' />
<cfset var value = '' />
<cfset arguments.options = variables.extend.extend(defaults, arguments.options) />
<cfsavecontent variable="html">
<table class="datagrid <cfoutput>#arguments.options.class#</cfoutput>">
<tbody>
<cfset rowNum = 0 />
<cfloop from="#arguments.options.startRow#" to="#min(arrayLen(arguments.data), arguments.options.startRow + arguments.options.numPerPage)#" index="i">
<cfset item = arguments.data[i] />
<cfset rowNum++ />
<cfoutput>
<tr>
<cfset counter = 0 />
<cfloop array="#variables.columns#" index="col">
<td class="#col.key# #col.class# column-#counter++#">
<cfset value = item[col.key] />
#createLink(value, col, data, rowNum, counter, arguments.options)#
</td>
</cfloop>
</tr>
</cfoutput>
</cfloop>
</tbody>
</table>
</cfsavecontent>
<cfreturn html />
</cffunction>
</cfcomponent>
<cfcomponent output="false">
<cffunction name="init" access="public" returntype="any" output="false">
<cfreturn this />
</cffunction>
<cffunction name="extend" access="public" output="false">
<cfargument name="defaults" type="struct" required="true" />
<cfargument name="original" type="struct" default="#{}#" />
<cfargument name="depth" type="numeric" default="1" />
<cfset var extended = duplicate(arguments.original) />
<cfset var i = '' />
<!--- Loop through and test each value in the values struct and see if it has been set already --->
<cfloop list="#structKeyList(arguments.defaults)#" index="i">
<cfif not structKeyExists(extended, i)>
<cfset extended[i] = arguments.defaults[i] />
<cfelseif (arguments.depth gt 1 or arguments.depth lt 0) and isStruct(arguments.defaults[i]) and isStruct(extended[i])>
<cfset extended[i] = extend(arguments.defaults[i], extended[i], arguments.depth - 1) />
</cfif>
</cfloop>
<cfreturn extended />
</cffunction>
</cfcomponent>
<cfset theUrl = createObject('component', 'urlRewrite').init('') />
<cfset datagrid = createObject('component', 'datagrid').init() />
<cfset datagrid.addColumn({
key = 'name',
link = {
'userID' = 'userID'
}
}) />
<cfset data = [
{
userID = 1,
name = "John"
}
] />
<cfoutput>#datagrid.toHTML(data, {
theUrl = theUrl
})#</cfoutput>
<cfcomponent output="false">
<cffunction name="init" access="public" returntype="any" output="false">
<cfargument name="masterBase" type="any" default="" />
<cfargument name="options" type="struct" default="#{}#" />
<cfset variables.urlOptions = {
start = '',
startChar = '?',
ampEncodeChar = '&amp;',
eqEncodeChar = '='
} />
<cfset variables.extend = createObject('component', 'extend').init() />
<cfset variables.locations = {} />
<cfset variables.locations[''] = {} />
<cfreturn this />
</cffunction>
<cffunction name="__findLocation" access="private" returntype="struct" output="false">
<cfargument name="locationName" type="string" required="true" />
<cfset arguments.locationName = trim(arguments.locationName) />
<!--- Check for valid location --->
<cfif not __has(arguments.locationName)>
<cfset variables.locations[arguments.locationName] = variables.extend.extend({}, variables.locations['']) />
</cfif>
<cfreturn variables.locations[arguments.locationName] />
</cffunction>
<cffunction name="__get" access="private" returntype="string" output="false">
<cfargument name="locationName" type="string" default="" />
<cfargument name="useEncoded" type="boolean" default="true" />
<cfargument name="options" type="struct" default="#{}#" />
<cfset var formatted = '' />
<cfset var current = '' />
<cfset var ampChar = '' />
<cfset var eqChar = '' />
<cfset var currentLocation = __findLocation(arguments.locationName) />
<cfset var getOptions = '' />
<!--- Extend the options --->
<cfset getOptions = variables.extend.extend(variables.urlOptions, arguments.options) />
<cfset ampChar = getOptions.ampEncodeChar />
<cfset eqChar = getOptions.eqEncodeChar />
<cfif not structKeyExists(getOptions, 'keys')>
<cfset getOptions.keys = structKeyList(currentLocation) />
</cfif>
<!--- Add each variable --->
<cftry>
<cfloop list="#getOptions.keys#" index="current">
<cfset formatted &= current & eqChar & currentLocation[current] & ampChar />
</cfloop>
<cfcatch type="any">
<cfdump var="#currentLocation#" label="Url currentLocation" />
<cfdump var="#variables.locations#" label="Url variables.locations" />
<cfrethrow />
</cfcatch>
</cftry>
<cfreturn formatted />
</cffunction>
<cffunction name="__has" access="private" returntype="boolean" output="false">
<cfargument name="locationName" type="string" default="" />
<!--- Check if is master --->
<cfif arguments.locationName eq ''>
<cfreturn true />
</cfif>
<cfreturn structKeyExists(variables.locations, arguments.locationName) />
</cffunction>
<cffunction name="onMissingMethod" access="public" returntype="any" output="false">
<cfargument name="missingMethodName" type="string" required="true" />
<cfargument name="missingMethodArguments" type="struct" required="true" />
<cfset var findParts = '' />
<cfset var name = '' />
<cfset var extra = '' />
<!--- Since railo has uppercase missingMethodName need to have missingMethodName in lowercase --->
<cfset arguments.missingMethodName = lCase(arguments.missingMethodName) />
<!--- Find the parts of the function name we are interested in --->
<cfset findParts = reFind('^(get|has|set)(.*)', arguments.missingMethodName, 1, true) />
<!--- Check if not one that we are equiped to handle --->
<cfif not findParts.pos[1]>
<cfthrow message="The #arguments.missingMethodName# method was not found" />
</cfif>
<!--- Set the name --->
<cfset name = left(arguments.missingMethodName, findParts.len[2]) />
<!--- Set the extra information --->
<cfif findParts.len[3]>
<cfset extra = mid(arguments.missingMethodName, findParts.pos[3], findParts.len[3]) />
</cfif>
<!--- Determine what we are really doing --->
<cfswitch expression="#name#">
<cfcase value="get">
<cfif len(extra)>
<cfset arrayPrepend(arguments.missingMethodArguments, extra) />
</cfif>
<cfreturn __get(argumentCollection = arguments.missingMethodArguments) />
</cfcase>
<cfcase value="has">
<cfif arrayLen(arguments.missingMethodArguments) eq 1>
<cfreturn __has(arguments.missingMethodArguments[1]) />
</cfif>
<cfreturn __has(extra) />
</cfcase>
<cfcase value="set">
<cfif arrayLen(arguments.missingMethodArguments) eq 3>
<cfreturn __set(arguments.missingMethodArguments[1], arguments.missingMethodArguments[2], arguments.missingMethodArguments[3]) />
</cfif>
<cfreturn __set(extra, arguments.missingMethodArguments[1], arguments.missingMethodArguments[2]) />
</cfcase>
</cfswitch>
<cfthrow message="The #arguments.missingMethodName# method was not found" />
</cffunction>
<cffunction name="__set" access="private" returntype="void" output="false">
<cfargument name="locationName" type="string" required="true" />
<cfargument name="varName" type="string" required="true" />
<cfargument name="varValue" type="any" required="true" />
<cfset var currentLocation = '' />
<!--- Get the location --->
<cfset currentLocation = __findLocation(arguments.locationName) />
<!--- Set the value --->
<cfset currentLocation[arguments.varName] = arguments.varValue />
</cffunction>
</cfcomponent>
component extends="url" {
public component function init(any masterBase = '', struct options = {}) {
if(!structKeyExists(arguments.options, 'rewriteBase') || arguments.options.rewriteBase eq '') {
arguments.options['rewriteBase'] = '_base';
}
super.init(argumentCollection = arguments);
return this;
}
private string function __get( string locationName = '', boolean useEncoded = true, struct options = {} ) {
var keys = '';
var locate = '';
var currentLocation = __findLocation(arguments.locationName);
// Extend the options
arguments.options = variables.extend.extend(variables.urlOptions, arguments.options);
arguments.options.keys = structKeyList(currentLocation);
try {
return super.__get(argumentCollection = arguments);
} catch(any e) {
writeDump(var = currentLocation, label = 'Rewrite currentlocation');
writeDump(var = variables.locations, label = 'Rewrite variables.locations');
writeDump(var = e, label = 'Original Error');
abort;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment