PageRenderTime 24ms CodeModel.GetById 8ms app.highlight 7ms RepoModel.GetById 2ms app.codeStats 0ms

/wheels/dispatch/request.cfm

http://raihan.googlecode.com/
ColdFusion | 412 lines | 397 code | 15 blank | 0 comment | 48 complexity | 2deb6fbb32a2773f6f3f5bf22cfae214 MD5 | raw file
  1<cffunction name="$init" returntype="any" access="public" output="false">
  2	<cfreturn this>
  3</cffunction>
  4
  5<cffunction name="$createParams" returntype="struct" access="public" output="false">
  6	<cfargument name="path" type="string" required="true">
  7	<cfargument name="route" type="struct" required="true">
  8	<cfargument name="formScope" type="struct" required="true">
  9	<cfargument name="urlScope" type="struct" required="true">
 10	<cfscript>
 11		var loc = {};
 12
 13		loc.params = {};
 14		loc.params = $mergeURLAndFormScopes(loc.params, arguments.urlScope, arguments.formScope);
 15		loc.params = $mergeRoutePattern(loc.params, arguments.route, arguments.path);
 16		loc.params = $decryptParams(loc.params);
 17		loc.params = $translateBlankCheckBoxSubmissions(loc.params);
 18		loc.params = $translateDatePartSubmissions(loc.params);
 19		loc.params = $createNestedParamStruct(loc.params);
 20		/***********************************************
 21		*	We now do the routing and controller
 22		*	params after we have built all other params
 23		*	so that we don't have more logic around
 24		*	params in arrays
 25		***********************************************/
 26		loc.params = $ensureControllerAndAction(loc.params, arguments.route);
 27		loc.params = $addRouteFormat(loc.params, arguments.route);
 28		loc.params = $addRouteName(loc.params, arguments.route);
 29	</cfscript>
 30	<cfreturn loc.params>
 31</cffunction>
 32
 33<cffunction name="$createNestedParamStruct" returntype="struct" access="public" output="false">
 34	<cfargument name="params" type="struct" required="true" />
 35	<cfscript>
 36		var loc = {};
 37		for (loc.key in arguments.params)
 38		{
 39			if (Find("[", loc.key) && Right(loc.key, 1) == "]")
 40			{
 41				// object form field
 42				loc.name = SpanExcluding(loc.key, "[");
 43				
 44				// we split the key into an array so the developer can have unlimited levels of params passed in
 45				loc.nested = ListToArray(ReplaceList(loc.key, loc.name & "[,]", ""), "[", true);
 46				if (!StructKeyExists(arguments.params, loc.name))
 47					arguments.params[loc.name] = {};
 48				
 49				loc.struct = arguments.params[loc.name]; // we need a reference to the struct so we can nest other structs if needed
 50				loc.iEnd = ArrayLen(loc.nested);
 51				for (loc.i = 1; loc.i lte loc.iEnd; loc.i++) // looping over the array allows for infinite nesting
 52				{
 53					loc.item = loc.nested[loc.i];
 54					if (!StructKeyExists(loc.struct, loc.item))
 55						loc.struct[loc.item] = {};
 56					if (loc.i != loc.iEnd)
 57						loc.struct = loc.struct[loc.item]; // pass the new reference (structs pass a reference instead of a copy) to the next iteration
 58					else
 59						loc.struct[loc.item] = arguments.params[loc.key];
 60				}
 61				// delete the original key so it doesn't show up in the params
 62				StructDelete(arguments.params, loc.key, false);
 63			}
 64		}
 65	</cfscript>
 66	<cfreturn arguments.params />
 67</cffunction>
 68
 69<cffunction name="$findMatchingRoute" returntype="struct" access="public" output="false">
 70	<cfargument name="path" type="string" required="true">
 71	<cfscript>
 72		var loc = {};
 73	
 74		loc.iEnd = ArrayLen(application.wheels.routes);
 75		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
 76		{
 77			loc.format = "";
 78			if (StructKeyExists(application.wheels.routes[loc.i], "format"))
 79				loc.format = application.wheels.routes[loc.i].format;
 80				
 81			loc.currentRoute = application.wheels.routes[loc.i].pattern;
 82			if (loc.currentRoute == "*") {
 83				loc.returnValue = application.wheels.routes[loc.i];
 84				break;
 85			} 
 86			else if (arguments.path == "" && loc.currentRoute == "")
 87			{
 88				loc.returnValue = application.wheels.routes[loc.i];
 89				break;
 90			}
 91			else if (ListLen(arguments.path, "/") gte ListLen(loc.currentRoute, "/") && loc.currentRoute != "")
 92			{
 93				loc.match = true;
 94				loc.jEnd = ListLen(loc.currentRoute, "/");
 95				for (loc.j=1; loc.j <= loc.jEnd; loc.j++)
 96				{
 97					loc.item = ListGetAt(loc.currentRoute, loc.j, "/");
 98					loc.thisRoute = ReplaceList(loc.item, "[,]", "");
 99					loc.thisURL = ListGetAt(arguments.path, loc.j, "/");
100					if (Left(loc.item, 1) != "[" && loc.thisRoute != loc.thisURL)
101						loc.match = false;
102				}
103				if (loc.match)
104				{
105					loc.returnValue = application.wheels.routes[loc.i];
106					if (len(loc.format))
107					{
108						loc.returnValue[ReplaceList(loc.format, "[,]", "")] = $getFormatFromRequest(pathInfo=arguments.path);
109					}
110					break;
111				}
112			}
113		}
114		if (!StructKeyExists(loc, "returnValue"))
115			$throw(type="Wheels.RouteNotFound", message="Wheels couldn't find a route that matched this request.", extendedInfo="Make sure there is a route setup in your `config/routes.cfm` file that matches the `#arguments.path#` request.");
116		</cfscript>
117		<cfreturn loc.returnValue>
118</cffunction>
119
120<cffunction name="$getPathFromRequest" returntype="string" access="public" output="false">
121	<cfargument name="pathInfo" type="string" required="true">
122	<cfargument name="scriptName" type="string" required="true">
123	<cfscript>
124		var returnValue = "";
125		// we want the path without the leading "/" so this is why we do some checking here
126		if (arguments.pathInfo == arguments.scriptName || arguments.pathInfo == "/" || arguments.pathInfo == "")
127			returnValue = "";
128		else
129			returnValue = Right(arguments.pathInfo, Len(arguments.pathInfo)-1);
130	</cfscript>
131	<cfreturn returnValue>
132</cffunction>
133
134<cffunction name="$getFormatFromRequest" returntype="string" access="public" output="false">
135	<cfargument name="pathInfo" type="string" required="true">
136	<cfscript>
137		var returnValue = "";
138		if (Find(".", arguments.pathInfo))
139			returnValue = ListLast(arguments.pathInfo, ".");
140	</cfscript>
141	<cfreturn returnValue>
142</cffunction>
143
144<cffunction name="$request" returntype="string" access="public" output="false">
145	<cfargument name="pathInfo" type="string" required="false" default="#request.cgi.path_info#">
146	<cfargument name="scriptName" type="string" required="false" default="#request.cgi.script_name#">
147	<cfargument name="formScope" type="struct" required="false" default="#form#">
148	<cfargument name="urlScope" type="struct" required="false" default="#url#">
149	<cfscript>
150		var loc = {};
151		if (application.wheels.showDebugInformation)
152			$debugPoint("setup");
153
154		loc.params = $paramParser(argumentCollection=arguments);
155		
156		// set params in the request scope as well so we can display it in the debug info outside of the dispatch / controller context
157		request.wheels.params = loc.params;
158
159		if (application.wheels.showDebugInformation)
160			$debugPoint("setup");
161
162		// create the requested controller
163		loc.controller = controller(name=loc.params.controller, params=loc.params);
164		
165		// if the controller fails to process, instantiate a new controller and try again
166		if (!loc.controller.$processAction())
167		{
168			loc.controller = controller(name=loc.params.controller, params=loc.params);
169			loc.controller.$processAction();
170		}
171		
172		// if there is a delayed redirect pending we execute it here thus halting the rest of the request
173		if (loc.controller.$performedRedirect())
174			$location(argumentCollection=loc.controller.$getRedirect());
175
176		// clear out the flash (note that this is not done for redirects since the processing does not get here)
177		loc.controller.$flashClear();
178	</cfscript>
179	<cfreturn loc.controller.response()>
180</cffunction>
181
182<cffunction name="$paramParser" returntype="struct" access="public" output="false">
183	<cfargument name="pathInfo" type="string" required="false" default="#request.cgi.path_info#">
184	<cfargument name="scriptName" type="string" required="false" default="#request.cgi.script_name#">
185	<cfargument name="formScope" type="struct" required="false" default="#form#">
186	<cfargument name="urlScope" type="struct" required="false" default="#url#">
187	<cfscript>
188		var loc = {};
189		loc.path = $getPathFromRequest(pathInfo=arguments.pathInfo, scriptName=arguments.scriptName);
190		loc.route = $findMatchingRoute(path=loc.path);
191		return $createParams(path=loc.path, route=loc.route, formScope=arguments.formScope, urlScope=arguments.urlScope);
192	</cfscript>
193</cffunction>
194
195<cffunction name="$mergeURLAndFormScopes" returntype="struct" access="public" output="false"
196	hint="merges the url and form scope into a single structure. url scope has presidence">
197	<cfargument name="params" type="struct" required="true">
198	<cfargument name="urlScope" type="struct" required="true">
199	<cfargument name="formScope" type="struct" required="true">
200	<cfscript>
201		structAppend(arguments.params, arguments.formScope, true);
202		structAppend(arguments.params, arguments.urlScope, true);
203	
204		// get rid of the fieldnames
205		StructDelete(arguments.params, "fieldnames", false);
206	</cfscript>
207	<cfreturn arguments.params>
208</cffunction>
209
210<cffunction name="$mergeRoutePattern" returntype="struct" access="public" output="false"
211	hint="parses the route pattern. identifies the variable markers within the pattern and assigns the value from the url variables with the path">
212	<cfargument name="params" type="struct" required="true">
213	<cfargument name="route" type="struct" required="true">
214	<cfargument name="path" type="string" required="true">
215	<cfscript>
216		var loc = {};
217		loc.iEnd = ListLen(arguments.route.pattern, "/");
218		if (StructKeyExists(arguments.route, "format") AND len(arguments.route.format))
219		{
220			arguments.path = Reverse(ListRest(Reverse(arguments.path), "."));
221		}
222		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
223		{
224			loc.item = ListGetAt(arguments.route.pattern, loc.i, "/");
225			if (Left(loc.item, 1) == "[")
226			{
227				arguments.params[ReplaceList(loc.item, "[,]", "")] = ListGetAt(arguments.path, loc.i, "/");
228			}
229		}
230	</cfscript>
231	<cfreturn arguments.params>
232</cffunction>
233
234<cffunction name="$decryptParams" returntype="struct" access="public" output="false"
235	hint="loops through the params struct passed in and attempts to deobfuscate them. ignores the controller and action params values.">
236	<cfargument name="params" type="struct" required="true">
237	<cfscript>
238		var loc = {};
239		if (application.wheels.obfuscateUrls)
240		{
241			for (loc.key in arguments.params)
242			{
243				if (loc.key != "controller" && loc.key != "action")
244				{
245					try
246					{
247						arguments.params[loc.key] = deobfuscateParam(arguments.params[loc.key]);
248					}
249					catch(Any e)
250					{}
251				}
252			}
253		}
254	</cfscript>
255	<cfreturn arguments.params>
256</cffunction>
257
258<cffunction name="$translateBlankCheckBoxSubmissions" returntype="struct" access="public" output="false"
259	hint="loops through the params struct and handle the cases where checkboxes are unchecked">
260	<cfargument name="params" type="struct" required="true">
261	<cfscript>
262		var loc = {};
263		for (loc.key in arguments.params)
264		{
265			if (FindNoCase("($checkbox)", loc.key))
266			{
267				// if no other form parameter exists with this name it means that the checkbox was left 
268				// blank and therefore we force the value to the unchecked values for the checkbox 
269				// (to get around the problem that unchecked checkboxes don't post at all)
270				loc.formParamName = ReplaceNoCase(loc.key, "($checkbox)", "");
271				if (!StructKeyExists(arguments.params, loc.formParamName))
272				{
273					arguments.params[loc.formParamName] = arguments.params[loc.key];
274				}
275				StructDelete(arguments.params, loc.key, false);
276			}
277		}
278	</cfscript>
279	<cfreturn arguments.params>
280</cffunction>
281
282<cffunction name="$translateDatePartSubmissions" returntype="struct" access="public" output="false"
283	hint="combines date parts into a single value">
284	<cfargument name="params" type="struct" required="true">
285	<cfscript>
286		var loc = {};
287		loc.dates = {};
288
289		for (loc.key in arguments.params)
290		{
291			if (REFindNoCase(".*\((\$year|\$month|\$day|\$hour|\$minute|\$second|\$ampm)\)$", loc.key))
292			{
293				loc.temp = ListToArray(loc.key, "(");
294				loc.firstKey = loc.temp[1];
295				loc.secondKey = SpanExcluding(loc.temp[2], ")");
296	
297				if (!StructKeyExists(loc.dates, loc.firstKey))
298				{
299					loc.dates[loc.firstKey] = {};
300				}
301				loc.dates[loc.firstKey][ReplaceNoCase(loc.secondKey, "$", "")] = arguments.params[loc.key];
302			}
303		}
304
305		for (loc.key in loc.dates)
306		{
307			if (!StructKeyExists(loc.dates[loc.key], "year"))
308			{
309				loc.dates[loc.key].year = 1899;
310			}
311			if (!StructKeyExists(loc.dates[loc.key], "month"))
312			{
313				loc.dates[loc.key].month = 1;
314			}
315			if (!StructKeyExists(loc.dates[loc.key], "day"))
316			{
317				loc.dates[loc.key].day = 1;
318			}
319			if (!StructKeyExists(loc.dates[loc.key], "hour"))
320			{
321				loc.dates[loc.key].hour = 0;
322			}
323			if (!StructKeyExists(loc.dates[loc.key], "minute"))
324			{
325				loc.dates[loc.key].minute = 0;
326			}
327			if (!StructKeyExists(loc.dates[loc.key], "second"))
328			{
329				loc.dates[loc.key].second = 0;
330			}
331			if (StructKeyExists(loc.dates[loc.key], "ampm"))
332			{
333				if (loc.dates[loc.key].ampm IS "AM" && loc.dates[loc.key].hour EQ 12)
334				{
335					loc.dates[loc.key].hour = 0;
336				}
337				else if (loc.dates[loc.key].ampm IS "PM")
338				{
339					loc.dates[loc.key].hour += 12;
340				}
341			}
342			if (!StructKeyExists(arguments.params, loc.key) || !IsArray(arguments.params[loc.key]))
343			{
344				arguments.params[loc.key] = [];
345			}
346			try
347			{
348				arguments.params[loc.key] = CreateDateTime(loc.dates[loc.key].year, loc.dates[loc.key].month, loc.dates[loc.key].day, loc.dates[loc.key].hour, loc.dates[loc.key].minute, loc.dates[loc.key].second);
349			}
350			catch(Any e)
351			{
352				arguments.params[loc.key] = "";
353			}
354			
355			StructDelete(arguments.params, "#loc.key#($year)", false);
356			StructDelete(arguments.params, "#loc.key#($month)", false);
357			StructDelete(arguments.params, "#loc.key#($day)", false);
358			StructDelete(arguments.params, "#loc.key#($hour)", false);
359			StructDelete(arguments.params, "#loc.key#($minute)", false);
360			StructDelete(arguments.params, "#loc.key#($second)", false);
361		}
362	</cfscript>
363	<cfreturn arguments.params>
364</cffunction>
365
366<cffunction name="$ensureControllerAndAction" returntype="struct" access="public" output="false"
367	hint="ensure that the controller and action params exists and camelized">
368	<cfargument name="params" type="struct" required="true">
369	<cfargument name="route" type="struct" required="true">
370	<cfscript>
371		if (!StructKeyExists(arguments.params, "controller"))
372		{
373			arguments.params.controller = arguments.route.controller;
374		}
375		if (!StructKeyExists(arguments.params, "action"))
376		{
377			arguments.params.action = arguments.route.action;
378		}
379
380		// convert controller to upperCamelCase and action to normal camelCase
381		arguments.params.controller = REReplace(arguments.params.controller, "(^|-)([a-z])", "\u\2", "all");
382		arguments.params.action = REReplace(arguments.params.action, "-([a-z])", "\u\1", "all");
383	</cfscript>
384	<cfreturn arguments.params>
385</cffunction>
386
387<cffunction name="$addRouteFormat" returntype="struct" access="public" output="false"
388	hint="adds in the format variable from the route if it exists">
389	<cfargument name="params" type="struct" required="true">
390	<cfargument name="route" type="struct" required="true">
391	<cfscript>
392		if (StructKeyExists(arguments.route, "formatVariable") && StructKeyExists(arguments.route, "format"))
393		{
394			arguments.params[arguments.route.formatVariable] = arguments.route.format;
395		}
396	</cfscript>
397	<cfreturn arguments.params>
398</cffunction>
399
400<cffunction name="$addRouteName" returntype="struct" access="public" output="false"
401	hint="adds in the name variable from the route if it exists">
402	<cfargument name="params" type="struct" required="true">
403	<cfargument name="route" type="struct" required="true">
404	<cfscript>
405		if (StructKeyExists(arguments.route, "name") && Len(arguments.route.name) && !StructKeyExists(arguments.params, "route"))
406		{
407			arguments.params.route = arguments.route.name;
408		}
409	</cfscript>
410	<cfreturn arguments.params>
411</cffunction>
412