root / framework / tags / fusebox550 / myFusebox.cfc

Revision 663, 19.3 kB (checked in by scorfield, 1 year ago)

Fixes #304 by tightening up skeleton app code for initialization and application naming. Also makes a
slight change to appinit to allow for the framework being initialized via a remote CFC call. It is not
an ideal change but it solves the basic problem.

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