- qpscanner/fusebox5/myFusebox.cfc
- 0.7.3
- 20 KB
- 482
1<!---
2Copyright 2006-2007 TeraTech, Inc. http://teratech.com/
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15--->
16<cfcomponent hint="I provide the per-request myFusebox data structure and some convenience methods.">
17 <cfscript>
18 this.version.runtime = "5.5.1";
19 //this.version.runtime = "5.5.0.#REReplace('$LastChangedRevision:683 $','[^0-9]','','all')#";
20
21 this.version.loader = "unknown";
22 this.version.transformer = "unknown";
23 this.version.parser = "unknown";
24
25 this.thisCircuit = "";
26 this.thisFuseaction = "";
27 this.thisPlugin = "";
28 this.thisPhase = "";
29 this.plugins = structNew();
30 this.parameters = structNew();
31
32 // the basic default is development-full-load mode:
33 this.parameters.load = true;
34 this.parameters.parse = true;
35 this.parameters.execute = true;
36 // FB5: new execution parameters:
37 this.parameters.clean = false; // don't delete parsed files by default
38 this.parameters.parseall = false; // don't compile all fuseactions by default
39
40 this.parameters.userProvidedLoadParameter = false;
41 this.parameters.userProvidedCleanParameter = false;
42 this.parameters.userProvidedParseParameter = false;
43 this.parameters.userProvidedParseAllParameter = false;
44 this.parameters.userProvidedExecuteParameter = false;
45
46 // stack frame for do/include parameters:
47 this.stack = structNew();
48
49 // FB55: ability to turn debug output off per-request:
50 this.showDebug = true;
51 </cfscript>
52
53 <cffunction name="init" returntype="myFusebox" access="public" output="false"
54 hint="I am the constructor.">
55 <cfargument name="appKey" type="string" required="true"
56 hint="I am FUSEBOX_APPLICATION_KEY." />
57 <cfargument name="attributes" type="struct" required="true"
58 hint="I am the attributes (URL and form variables) structure." />
59 <cfargument name="topLevelVariablesScope" type="any" required="true"
60 hint="I am the top-level variables scope." />
61
62 <cfset var theFusebox = structNew() />
63 <cfset var urlParam = "" />
64 <cfset var urlLastArg = "" />
65 <cfset var urlIsArg = true />
66 <cfset var pathInfo = CGI.PATH_INFO />
67
68 <cfset variables.variablesScope = arguments.topLevelVariablesScope />
69
70 <cfset variables.created = getTickCount() />
71 <cfset variables.log = arrayNew(1) />
72 <cfset variables.occurrence = structNew() />
73
74 <cfset variables.appKey = arguments.appKey />
75 <cfset variables.attributes = arguments.attributes />
76
77 <!--- FB5: indicates whether application was started on this request --->
78 <cfset this.applicationStart = false />
79
80 <!--- we can't guarantee the fusebox exists in application scope yet... --->
81 <cfif structKeyExists(application,variables.appKey)>
82 <cfset theFusebox = application[variables.appKey] />
83 </cfif>
84
85 <!--- default myFusebox.parameters depending on "mode" of the application set in fusebox.xml --->
86 <cfif structKeyExists(theFusebox,"mode")>
87 <cfswitch expression="#theFusebox.mode#">
88 <!--- FB41 backward compatibility - now deprecated --->
89 <cfcase value="development">
90 <cfif structKeyExists(theFusebox,"strictMode") and theFusebox.strictMode>
91 <!--- since we don't load fusebox.xml if we throw an exception, we must fixup the value for the next run --->
92 <cfset theFusebox.mode = "development-full-load" />
93 <cfthrow type="fusebox.badGrammar.deprecated"
94 message="Deprecated feature"
95 detail="'development' is a deprecated execution mode - use 'development-full-load' instead." />
96 </cfif>
97 <cfset this.parameters.load = true />
98 <cfset this.parameters.parse = true />
99 <cfset this.parameters.execute = true />
100 </cfcase>
101 <!--- FB5: replacement for old development mode --->
102 <cfcase value="development-full-load">
103 <cfset this.parameters.load = true />
104 <cfset this.parameters.parse = true />
105 <cfset this.parameters.execute = true />
106 </cfcase>
107 <!--- FB5: new option - does not load fusebox.xml and therefore does not (re-)load fuseboxApplication object --->
108 <cfcase value="development-circuit-load">
109 <cfset this.parameters.load = false />
110 <cfset this.parameters.parse = true />
111 <cfset this.parameters.execute = true />
112 </cfcase>
113 <cfcase value="production">
114 <cfset this.parameters.load = false />
115 <cfset this.parameters.parse = false />
116 <cfset this.parameters.execute = true />
117 </cfcase>
118 <cfdefaultcase>
119 <!--- since we don't load fusebox.xml if we throw an exception, we must fixup the value for the next run --->
120 <cfset theFusebox.mode = "development-full-load" />
121 <cfthrow type="fusebox.badGrammar.invalidParameterValue"
122 message="Parameter has invalid value"
123 detail="The parameter 'mode' must be one of 'development-full-load', 'development-circuit-load' or 'production' in the fusebox.xml file." />
124 </cfdefaultcase>
125 </cfswitch>
126 </cfif>
127
128 <!--- handle SES URLs if appropriate --->
129 <cfif structKeyExists(theFusebox,"queryStringStart") and theFusebox.queryStringStart is not "?">
130 <!--- looks like SES URL generation is enabled, process CGI.PATH_INFO (we add &= to catch improperly formed URLs) --->
131 <!--- ticket 313 - canonicalize pathInfo for IIS 5 --->
132 <cfif len(pathInfo) gt len(CGI.SCRIPT_NAME) and left(pathInfo,len(CGI.SCRIPT_NAME)) is CGI.SCRIPT_NAME>
133 <cfset pathInfo = right(pathInfo,len(pathInfo)-len(CGI.SCRIPT_NAME)) />
134 </cfif>
135 <cfloop list="#pathInfo#" index="urlParam"
136 delimiters="#theFusebox.queryStringStart##theFusebox.queryStringSeparator##theFusebox.queryStringEqual#&=">
137 <cfif urlIsArg>
138 <cfset urlLastArg = urlParam />
139 <cfelse>
140 <cfset variables.attributes[urlLastArg] = urlParam />
141 </cfif>
142 <cfset urlIsArg = not urlIsArg />
143 </cfloop>
144 </cfif>
145
146 <!--- did the user pass in any special "fuseboxDOT" parameters for this request? --->
147 <!--- If so, process them --->
148 <!--- note: only if attributes.fusebox.password matches the application password --->
149 <cfif not structKeyExists(variables.attributes,"fusebox.password")>
150 <cfset variables.attributes["fusebox.password"] = "" />
151 </cfif>
152 <cfif structKeyExists(theFusebox,"password") and
153 theFusebox.password is variables.attributes['fusebox.password']>
154 <!--- FB5: does a load and wipes the parsed files out --->
155 <cfif structKeyExists(variables.attributes,'fusebox.loadclean') and isBoolean(variables.attributes['fusebox.loadclean'])>
156 <cfset this.parameters.load = variables.attributes['fusebox.loadclean'] />
157 <cfset this.parameters.clean = variables.attributes['fusebox.loadclean'] />
158 <cfset this.parameters.userProvidedLoadParameter = true />
159 <cfset this.parameters.userProvidedCleanParameter = true />
160 </cfif>
161 <cfif structKeyExists(variables.attributes,'fusebox.load') and isBoolean(variables.attributes['fusebox.load'])>
162 <cfset this.parameters.load = variables.attributes['fusebox.load'] />
163 <cfset this.parameters.userProvidedLoadParameter = true />
164 </cfif>
165 <cfif structKeyExists(variables.attributes,'fusebox.parseall') and isBoolean(variables.attributes['fusebox.parseall'])>
166 <cfset this.parameters.parse = variables.attributes['fusebox.parseall'] />
167 <cfset this.parameters.parseall = variables.attributes['fusebox.parseall'] />
168 <cfif this.parameters.parseall>
169 <cfset this.parameters.load = true />
170 </cfif>
171 <cfset this.parameters.userProvidedParseParameter = true />
172 <cfset this.parameters.userProvidedParseAllParameter = true />
173 </cfif>
174 <cfif structKeyExists(variables.attributes,'fusebox.parse') and isBoolean(variables.attributes['fusebox.parse'])>
175 <cfset this.parameters.parse = variables.attributes['fusebox.parse'] />
176 <cfset this.parameters.userProvidedParseParameter = true />
177 </cfif>
178 <cfif structKeyExists(variables.attributes,'fusebox.execute') and isBoolean(variables.attributes['fusebox.execute'])>
179 <cfset this.parameters.execute = variables.attributes['fusebox.execute'] />
180 <cfset this.parameters.userProvidedExecuteParameter = true />
181 </cfif>
182 </cfif>
183
184 <!---
185 force a load if the runtime and core versions differ: this allows a new
186 version to be dropped in and the framework will automatically reload!
187 note: that we must *force* a load, by pretending this is user-provided!
188 --->
189 <cfif structKeyExists(theFusebox,"getVersion") and
190 isCustomFunction(theFusebox.getVersion)>
191 <cfif this.version.runtime is not theFusebox.getVersion()>
192 <cfset this.parameters.userProvidedLoadParameter = true />
193 <cfset this.parameters.load = true />
194 </cfif>
195 <cfelse>
196 <!--- hmm, doesn't look like the core is present (or it's not FB5 Alpha 2 or higher) --->
197 <cfset this.parameters.userProvidedLoadParameter = true />
198 <cfset this.parameters.load = true />
199 </cfif>
200
201 <!--- if the fusebox doesn't already exist we definitely want to reload --->
202 <cfif structKeyExists(theFusebox,"isFullyLoaded") and
203 theFusebox.isFullyLoaded>
204 <!--- if fully loaded, leave the load parameter alone --->
205 <cfelse>
206 <cfset this.parameters.load = true />
207 </cfif>
208
209 <cfreturn this />
210 </cffunction>
211
212 <cffunction name="getApplication" returntype="any" access="public" output="false"
213 hint="I am a convenience method to return the fuseboxApplication object without needing to know reference application scope or the FUSEBOX_APPLICATION_KEY variable.">
214
215 <!---
216 this is a bit of a hack since we're accessing application scope directly
217 but it's probably cleaner than exposing a method to allow fuseboxApplication
218 to inject itself back into myFusebox during compileRequest()...
219 --->
220 <cfreturn application[variables.appKey] />
221
222 </cffunction>
223
224 <cffunction name="getApplicationData" returntype="struct" access="public" output="false"
225 hint="I am a convenience method to return a reference to the application data cache.">
226
227 <cfreturn getApplication().getApplicationData() />
228
229 </cffunction>
230
231 <cffunction name="getCurrentCircuit" returntype="any" access="public" output="false"
232 hint="I am a convenience method to return the current Fusebox circuit object.">
233
234 <cfreturn getApplication().circuits[this.thisCircuit] />
235
236 </cffunction>
237
238 <cffunction name="getCurrentFuseaction" returntype="any" access="public" output="false"
239 hint="I am a convenience method to return the current fuseboxAction (fuseaction) object.">
240
241 <cfreturn getCurrentCircuit().fuseactions[this.thisFuseaction] />
242
243 </cffunction>
244
245 <cffunction name="getOriginalCircuit" returntype="any" access="public" output="false"
246 hint="I am a convenience method to return the original Fusebox circuit object.">
247
248 <cfreturn getApplication().circuits[this.originalCircuit] />
249
250 </cffunction>
251
252 <cffunction name="getOriginalFuseaction" returntype="any" access="public" output="false"
253 hint="I am a convenience method to return the original fuseboxAction (fuseaction) object.">
254
255 <cfreturn getCurrentCircuit().fuseactions[this.originalFuseaction] />
256
257 </cffunction>
258
259 <cffunction name="getSelf" returntype="string" access="public" output="false"
260 hint="I return the 'self' string, e.g., index.cfm.">
261
262 <cfif not structKeyExists(variables,"self")>
263 <cfset variables.self = getApplication().self />
264 </cfif>
265
266 <cfreturn variables.self />
267
268 </cffunction>
269
270 <cffunction name="setSelf" returntype="void" access="public" output="false"
271 hint="I override the default value of 'self' and I also reset the value of 'myself'.">
272 <cfargument name="self" type="string" required="true"
273 hint="I am the new value of 'self', e.g., /myapp/entry.cfm" />
274
275 <cfset variables.self = arguments.self />
276 <!--- reset myself for consistency with self --->
277 <cfset variables.myself = getApplication().getDefaultMyself(variables.self) />
278
279 </cffunction>
280
281 <cffunction name="getMyself" returntype="string" access="public" output="false"
282 hint="I return the 'myself' string, e.g., index.cfm?fuseaction=.">
283
284 <cfif not structKeyExists(variables,"myself")>
285 <cfset variables.myself = getApplication().myself />
286 </cfif>
287
288 <cfreturn variables.myself />
289
290 </cffunction>
291
292 <cffunction name="setMyself" returntype="void" access="public" output="false"
293 hint="I override the default value of 'myself'.">
294 <cfargument name="myself" type="string" required="true"
295 hint="I am the new value of 'myself'." />
296
297 <cfset variables.myself = arguments.myself />
298
299 </cffunction>
300
301 <cffunction name="do" returntype="string" access="public" output="true"
302 hint="I compile and execute a specific fuseaction.">
303 <cfargument name="action" type="string" required="true"
304 hint="I am the full name of the requested fuseaction (circuit.fuseaction)." />
305 <cfargument name="contentVariable" type="string" default=""
306 hint="I indicate an attributes / event scope variable in which to store the output." />
307 <cfargument name="returnOutput" type="boolean" default="false"
308 hint="I indicate whether to display output (false - default) or return the output (true)." />
309 <cfargument name="append" type="boolean" default="false"
310 hint="I indicate whether to append output (false - default) to the content variable." />
311
312 <cfset var c = this.thisCircuit />
313 <cfset var f = this.thisFuseaction />
314 <cfset var output =
315 getApplication().do(
316 arguments.action,
317 this,
318 arguments.returnOutput or arguments.contentVariable is not "") />
319
320 <cfset this.thisFuseaction = f />
321 <cfset this.thisCircuit = c />
322
323 <cfif arguments.contentVariable is not "">
324 <!--- ticket #290 - allow append on content variables --->
325 <cfif structKeyExists(variables.variablesScope,arguments.contentVariable) and arguments.append>
326 <cfset variables.variablesScope[arguments.contentVariable] = variables.variablesScope[arguments.contentVariable] & output />
327 <cfelse>
328 <cfset variables.variablesScope[arguments.contentVariable] = output />
329 </cfif>
330 </cfif>
331
332 <cfreturn output />
333
334 </cffunction>
335
336 <cffunction name="relocate" returntype="void" access="public" output="true"
337 hint="I provide the same functionality as the relocate verb.">
338 <cfargument name="url" type="string" required="false" />
339 <cfargument name="xfa" type="string" required="false" />
340 <cfargument name="addtoken" type="boolean" default="false" />
341 <cfargument name="type" type="string" default="client" />
342
343 <cfset var theUrl = "" />
344
345 <!--- url/xfa - exactly one is required --->
346 <cfif structKeyExists(arguments,"url")>
347 <cfif structKeyExists(arguments,"xfa")>
348 <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
349 message="Required attribute is missing"
350 detail="Either the attribute 'url' or 'xfa' is required, for a 'relocate' verb in fuseaction #this.thiscircuit#.#this.thisFuseaction#." />
351 <cfelse>
352 <cfset theUrl = arguments.url />
353 </cfif>
354 <cfelseif structKeyExists(arguments,"xfa")>
355 <cfset theUrl = getMyself() & variables.variablesScope.xfa[arguments.xfa] />
356 <cfelse>
357 <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
358 message="Required attribute is missing"
359 detail="Either the attribute 'url' or 'xfa' is required, for a 'relocate' verb in fuseaction #this.thiscircuit#.#this.thisFuseaction#." />
360 </cfif>
361
362 <!--- type - server|client|moved - we do not support javascript here --->
363 <cfif arguments.type is "server">
364
365 <cfset getPageContext().forward(theUrl) />
366
367 <cfelseif arguments.type is "client">
368
369 <cflocation url="#theUrl#" addtoken="#arguments.addtoken#" />
370
371 <cfelseif arguments.type is "moved">
372
373 <cfheader statuscode="301" statustext="Moved Permanently" />
374 <cfheader name="Location" value="#theUrl#" />
375
376 <cfelse>
377 <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
378 message="Attribute has invalid value"
379 detail="The attribute 'type' must either be ""server"", ""client"" or ""moved"", for a 'relocate' verb in fuseaction #this.thisCircuit#.#this.thisFuseaction#." />
380 </cfif>
381
382 <cfabort />
383
384 </cffunction>
385
386 <cffunction name="variables" returntype="any" access="public" output="false" hint="I return the top-level variables scope.">
387
388 <cfreturn variables.variablesScope />
389
390 </cffunction>
391
392 <cffunction name="enterStackFrame" returntype="void" access="public" output="false"
393 hint="I create a new stack frame (for scoped parameters to do/include).">
394
395 <cfset var frame = structNew() />
396
397 <cfset frame.__fuseboxStack = this.stack />
398 <cfset this.stack = frame />
399
400 </cffunction>
401
402 <cffunction name="leaveStackFrame" returntype="void" access="public" output="false"
403 hint="I pop the last stack frame (for scoped parameters to do/include).">
404
405 <cfset this.stack = this.stack.__fuseboxStack />
406
407 </cffunction>
408
409 <cffunction name="trace" returntype="void" access="public" output="false"
410 hint="I add a line to the execution trace log.">
411 <cfargument name="type" hint="I am the type of trace (Fusebox, Compiler, Runtime are used by the framework)." />
412 <cfargument name="message" hint="I am the message to put in the execution trace." />
413
414 <cfset addTrace(getTickCount() - variables.created,arguments.type,arguments.message) />
415
416 </cffunction>
417
418 <cffunction name="addTrace" returntype="void" access="private" output="false"
419 hint="I add a detailed line to the execution trace log.">
420 <cfargument name="time" hint="I am the time taken to get to this point in the request." />
421 <cfargument name="type" hint="I am the type of trace." />
422 <cfargument name="message" hint="I am the trace message." />
423 <cfargument name="occurrence" default="0" hint="I am a placeholder for part of the struct that is added to the log." />
424
425 <cfif structKeyExists(variables.occurrence,arguments.message)>
426 <cfset variables.occurrence[arguments.message] = 1 + variables.occurrence[arguments.message] />
427 <cfelse>
428 <cfset variables.occurrence[arguments.message] = 1 />
429 </cfif>
430 <cfset arguments.occurrence = variables.occurrence[arguments.message] />
431 <cfset arrayAppend(variables.log,arguments) />
432
433 </cffunction>
434
435 <cffunction name="renderTrace" returntype="string" access="public" output="false" hint="I render the trace log as HTML.">
436
437 <cfset var result = "" />
438 <cfset var i = 0 />
439
440 <cfif this.showDebug>
441 <cfsavecontent variable="result">
442 <style type="text/css">
443 .fuseboxdebug {clear:both;padding-top:10px;}
444 .fuseboxdebug * {font-family:verdana,sans-serif;}
445 .fuseboxdebug h3 {margin:16px 0 16px 0;padding:0;border-bottom:1px solid #CCC;font-size:16px;}
446 .fuseboxdebug table th {font-size:11pt;text-align:left;}
447 .fuseboxdebug table tr.odd {background:#F9F9F9;}
448 .fuseboxdebug table tr.even {background:#FFF;}
449 .fuseboxdebug table td {border-bottom:1px solid #CCC;font-size:10pt;text-align:left;vertical-align:top;}
450 .fuseboxdebug table td.count {text-align:center;}
451 </style>
452 <div class="fuseboxdebug">
453 <h3>Fusebox debugging:</h3>
454 <table cellpadding="2" cellspacing="0" width="100%">
455 <tr>
456 <th>Time</td>
457 <th>Category</td>
458 <th>Message</td>
459 <th>Count</td>
460 </tr>
461 <cfloop index="i" from="1" to="#arrayLen(variables.log)#">
462 <cfoutput>
463 <cfif i mod 2>
464 <tr class="odd">
465 <cfelse>
466 <tr class="even">
467 </cfif>
468 <td>#variables.log[i].time#ms</td>
469 <td>#variables.log[i].type#</td>
470 <td>#variables.log[i].message#</td>
471 <td class="count">#variables.log[i].occurrence#</td>
472 </tr></cfoutput>
473 </cfloop>
474 </table>
475 </div>
476 </cfsavecontent>
477 </cfif>
478
479 <cfreturn result />
480
481 </cffunction>
482</cfcomponent>