root / framework / branches / dev / myFusebox.cfc

Revision 421, 14.7 kB (checked in by scorfield, 2 years ago)

Tidied up how circuit-as-cfc is handled so that CFCs are actually instantiated and invoked
(rather than included like the former hack proof of concept).

  • Property svn:keywords set to LastChangedRevision
Line 
1<!---
2Copyright 2006 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        // tidied up circuit-as-cfc
19        this.version.runtime     = "6.0.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        </cfscript>
49       
50        <cffunction name="init" returntype="myFusebox" access="public" output="false"
51                                hint="I am the constructor.">
52                <cfargument name="appKey" type="string" required="true"
53                                        hint="I am FUSEBOX_APPLICATION_KEY." />
54                <cfargument name="attributes" type="struct" required="true"
55                                        hint="I am the attributes (URL and form variables) structure." />
56                <cfargument name="topLevelVariablesScope" type="any" required="true"
57                                        hint="I am the top-level variables scope." />
58               
59                <cfset var theFusebox = structNew() />
60               
61                <cfset variables.topLevelVariablesScope = arguments.topLevelVariablesScope />
62               
63                <cfset variables.created = getTickCount() />
64                <cfset variables.log = arrayNew(1) />
65                <cfset variables.occurrence = structNew() />
66
67                <cfset variables.appKey = arguments.appKey />
68                <cfset variables.attributes = arguments.attributes />
69               
70                <!--- we can't guarantee the fusebox exists in application scope yet... --->
71                <cfif structKeyExists(application,variables.appKey)>
72                        <cfset theFusebox = application[variables.appKey] />
73                </cfif>
74               
75                <!--- default myFusebox.parameters depending on "mode" of the application set in fusebox.xml --->
76                <cfif structKeyExists(theFusebox,"mode")>
77                        <cfswitch expression="#theFusebox.mode#">
78                        <!--- FB41 backward compatibility - now deprecated --->
79                        <cfcase value="development">
80                                <cfif structKeyExists(theFusebox,"strictMode") and theFusebox.strictMode>
81                                        <!--- since we don't load fusebox.xml if we throw an exception, we must fixup the value for the next run --->
82                                        <cfset theFusebox.mode = "development-full-load" />
83                                        <cfthrow type="fusebox.badGrammar.deprecated"
84                                                        message="Deprecated feature"
85                                                        detail="'development' is a deprecated execution mode - use 'development-full-load' instead." />
86                                </cfif>
87                                <cfset this.parameters.load = true />
88                                <cfset this.parameters.parse = true />
89                                <cfset this.parameters.execute = true />
90                        </cfcase>
91                        <!--- FB5: replacement for old development mode --->
92                        <cfcase value="development-full-load">
93                                <cfset this.parameters.load = true />
94                                <cfset this.parameters.parse = true />
95                                <cfset this.parameters.execute = true />
96                        </cfcase>
97                        <!--- FB5: new option - does not load fusebox.xml and therefore does not (re-)load fuseboxApplication object --->
98                        <cfcase value="development-circuit-load">
99                                <cfset this.parameters.load = false />
100                                <cfset this.parameters.parse = true />
101                                <cfset this.parameters.execute = true />
102                        </cfcase>
103                        <cfcase value="production">
104                                <cfset this.parameters.load = false />
105                                <cfset this.parameters.parse = false />
106                                <cfset this.parameters.execute = true />
107                        </cfcase>
108                        <cfdefaultcase>
109                                <!--- since we don't load fusebox.xml if we throw an exception, we must fixup the value for the next run --->
110                                <cfset theFusebox.mode = "development-full-load" />
111                                <cfthrow type="fusebox.badGrammar.invalidParameterValue"
112                                                message="Parameter has invalid value"
113                                                detail="The parameter 'mode' must be one of 'development-full-load', 'development-circuit-load' or 'production' in the fusebox.xml file." />
114                        </cfdefaultcase>
115                        </cfswitch>
116                </cfif>
117
118                <!--- did the user pass in any special "fuseboxDOT" parameters for this request? --->
119                <!--- If so, process them --->
120                <!--- note: only if attributes.fusebox.password matches the application password --->
121                <cfif not structKeyExists(variables.attributes,"fusebox.password")>
122                        <cfset variables.attributes["fusebox.password"] = "" />
123                </cfif>
124                <cfif structKeyExists(theFusebox,"password") and
125                                theFusebox.password is variables.attributes['fusebox.password']>
126                        <!--- FB5: does a load and wipes the parsed files out --->
127                        <cfif structKeyExists(variables.attributes,'fusebox.loadclean') and isBoolean(variables.attributes['fusebox.loadclean'])>
128                                <cfset this.parameters.load = variables.attributes['fusebox.loadclean'] />
129                                <cfset this.parameters.clean = variables.attributes['fusebox.loadclean'] />
130                                <cfset this.parameters.userProvidedLoadParameter = true />
131                                <cfset this.parameters.userProvidedCleanParameter = true />
132                        </cfif>
133                        <cfif structKeyExists(variables.attributes,'fusebox.load') and isBoolean(variables.attributes['fusebox.load'])>
134                                <cfset this.parameters.load = variables.attributes['fusebox.load'] />
135                                <cfset this.parameters.userProvidedLoadParameter = true />
136                        </cfif>
137                        <cfif structKeyExists(variables.attributes,'fusebox.parseall') and isBoolean(variables.attributes['fusebox.parseall'])>
138                                <cfset this.parameters.parse = variables.attributes['fusebox.parseall'] />
139                                <cfset this.parameters.parseall = variables.attributes['fusebox.parseall'] />
140                                <cfif this.parameters.parseall>
141                                        <cfset this.parameters.load = true />
142                                </cfif>
143                                <cfset this.parameters.userProvidedParseParameter = true />
144                                <cfset this.parameters.userProvidedParseAllParameter = true />
145                        </cfif>
146                        <cfif structKeyExists(variables.attributes,'fusebox.parse') and isBoolean(variables.attributes['fusebox.parse'])>
147                                <cfset this.parameters.parse = variables.attributes['fusebox.parse'] />
148                                <cfset this.parameters.userProvidedParseParameter = true />
149                        </cfif>
150                        <cfif structKeyExists(variables.attributes,'fusebox.execute') and isBoolean(variables.attributes['fusebox.execute'])>
151                                <cfset this.parameters.execute = variables.attributes['fusebox.execute'] />
152                                <cfset this.parameters.userProvidedExecuteParameter = true />
153                        </cfif>
154                </cfif>
155               
156                <!---
157                        force a load if the runtime and core versions differ: this allows a new
158                        version to be dropped in and the framework will automatically reload!
159                        note: that we must *force* a load, by pretending this is user-provided!
160                --->
161                <cfif structKeyExists(theFusebox,"getVersion") and
162                                isCustomFunction(theFusebox.getVersion)>
163                        <cfif this.version.runtime is not theFusebox.getVersion()>
164                                <cfset this.parameters.userProvidedLoadParameter = true />
165                                <cfset this.parameters.load = true />
166                        </cfif>
167                <cfelse>
168                        <!--- hmm, doesn't look like the core is present (or it's not FB5 Alpha 2 or higher) --->
169                        <cfset this.parameters.userProvidedLoadParameter = true />
170                        <cfset this.parameters.load = true />
171                </cfif>
172
173                <!--- if the fusebox doesn't already exist we definitely want to reload --->
174                <cfif structKeyExists(theFusebox,"isFullyLoaded") and
175                                theFusebox.isFullyLoaded>
176                        <!--- if fully loaded, leave the load parameter alone --->
177                <cfelse>
178                        <cfset this.parameters.load = true />
179                </cfif>
180               
181                <cfreturn this />
182        </cffunction>
183       
184        <cffunction name="getApplication" returntype="any" access="public" output="false"
185                                hint="I am a convenience method to return the fuseboxApplication object without needing to know reference application scope or the FUSEBOX_APPLICATION_KEY variable.">
186       
187                <!---
188                        this is a bit of a hack since we're accessing application scope directly
189                        but it's probably cleaner than exposing a method to allow fuseboxApplication
190                        to inject itself back into myFusebox during compileRequest()...
191                --->
192                <cfreturn application[variables.appKey] />
193       
194        </cffunction>
195       
196        <cffunction name="getCurrentCircuit" returntype="any" access="public" output="false"
197                                hint="I am a convenience method to return the current Fusebox circuit object.">
198       
199                <cfreturn getApplication().circuits[this.thisCircuit] />
200       
201        </cffunction>
202       
203        <cffunction name="getCurrentFuseaction" returntype="any" access="public" output="false"
204                                hint="I am a convenience method to return the current fuseboxAction (fuseaction) object.">
205       
206                <cfreturn getCurrentCircuit().fuseactions[this.thisFuseaction] />
207       
208        </cffunction>
209       
210        <cffunction name="getSelf" returntype="string" access="public" output="false"
211                                hint="I return the 'self' string, e.g., index.cfm.">
212
213                <cfif not structKeyExists(variables,"self")>
214                        <cfset variables.self = getApplication().self />
215                </cfif>
216               
217                <cfreturn variables.self />
218
219        </cffunction>   
220       
221        <cffunction name="setSelf" returntype="void" access="public" output="false"
222                                hint="I override the default value of 'self' and I also reset the value of 'myself'.">
223                <cfargument name="self" type="string" required="true"
224                                        hint="I am the new value of 'self', e.g., /myapp/entry.cfm" />
225               
226                <cfset variables.self = arguments.self />
227                <!--- reset myself for consistency with self --->
228                <cfset variables.myself = getApplication().getDefaultMyself(variables.self) />
229               
230        </cffunction>
231
232        <cffunction name="getMyself" returntype="string" access="public" output="false"
233                                hint="I return the 'myself' string, e.g., index.cfm?fuseaction=.">
234
235                <cfif not structKeyExists(variables,"myself")>
236                        <cfset variables.myself = getApplication().myself />
237                </cfif>
238               
239                <cfreturn variables.myself />
240
241        </cffunction>   
242       
243        <cffunction name="setMyself" returntype="void" access="public" output="false"
244                                hint="I override the default value of 'myself'.">
245                <cfargument name="myself" type="string" required="true"
246                                        hint="I am the new value of 'myself'." />
247               
248                <cfset variables.myself = arguments.myself />
249               
250        </cffunction>
251
252        <cffunction name="getTopLevelVariablesScope" returntype="any" access="public" output="false"
253                                hint="I return the top-level variables scope.">
254               
255                <cfreturn variables.topLevelVariablesScope />
256               
257        </cffunction>
258       
259        <cffunction name="do" returntype="void" access="public" output="true"
260                                hint="I compile and execute a specific fuseaction.">
261                <cfargument name="action" type="string" required="true"
262                                        hint="I am the full name of the requested fuseaction (circuit.fuseaction)." />
263
264                <cfset getApplication().do(arguments.action,this) />
265               
266        </cffunction>
267       
268        <cffunction name="enterStackFrame" returntype="void" access="public" output="false"
269                                hint="I create a new stack frame (for scoped parameters to do/include).">
270               
271                <cfset var frame = structNew() />
272               
273                <cfset frame.__fuseboxStack = this.stack />
274                <cfset this.stack = frame />
275               
276        </cffunction>
277       
278        <cffunction name="leaveStackFrame" returntype="void" access="public" output="false"
279                                hint="I pop the last stack frame (for scoped parameters to do/include).">
280               
281                <cfset this.stack = this.stack.__fuseboxStack />
282               
283        </cffunction>
284       
285        <cffunction name="trace" returntype="void" access="public" output="false"
286                                hint="I add a line to the execution trace log.">
287                <cfargument name="type" hint="I am the type of trace (Fusebox, Compiler, Runtime are used by the framework)." />
288                <cfargument name="message" hint="I am the message to put in the execution trace." />
289               
290                <cfset addTrace(getTickCount() - variables.created,arguments.type,arguments.message) />
291               
292        </cffunction>
293
294        <cffunction name="addTrace" returntype="void" access="private" output="false"
295                                hint="I add a detailed line to the execution trace log.">
296                <cfargument name="time" hint="I am the time taken to get to this point in the request." />
297                <cfargument name="type" hint="I am the type of trace." />
298                <cfargument name="message" hint="I am the trace message." />
299                <cfargument name="occurrence" default="0" hint="I am a placeholder for part of the struct that is added to the log." />
300               
301                <cfif structKeyExists(variables.occurrence,arguments.message)>
302                        <cfset variables.occurrence[arguments.message] = 1 + variables.occurrence[arguments.message] />
303                <cfelse>
304                        <cfset variables.occurrence[arguments.message] = 1 />
305                </cfif>
306                <cfset arguments.occurrence = variables.occurrence[arguments.message] />
307                <cfset arrayAppend(variables.log,arguments) />
308               
309        </cffunction>
310       
311        <cffunction name="renderTrace" returntype="string" access="public" output="false" hint="I render the trace log as HTML.">
312               
313                <cfset var result = "" />
314                <cfset var i = 0 />
315               
316                <cfsavecontent variable="result">
317                        <br />
318                        <div style="clear:both;padding-top:10px;border-bottom:1px Solid #CCC;font-family:verdana;font-size:16px;font-weight:bold">Fusebox debugging:</div>
319                        <br />
320                        <table cellpadding="2" cellspacing="0" width="100%" style="border:1px Solid ##CCC;font-family:verdana;font-size:11pt;">
321                                <tr style="background:##EAEAEA">
322                                        <td style="border-bottom:1px Solid ##CCC;font-family:verdana;font-size:11pt;"><strong>Time</strong></td>
323                                        <td style="border-bottom:1px Solid ##CCC;font-family:verdana;font-size:11pt;"><strong>Category</strong></td>
324                                        <td style="border-bottom:1px Solid ##CCC;font-family:verdana;font-size:11pt;"><strong>Message</strong></td>
325                                        <td style="border-bottom:1px Solid ##CCC;font-family:verdana;font-size:11pt;"><strong>Count</strong></td>
326                                </tr>
327                                <cfloop index="i" from="1" to="#arrayLen(variables.log)#">
328                                        <cfoutput>
329                                                <cfif i mod 2>
330                                                        <tr style="background:##F9F9F9">
331                                                <cfelse>
332                                                        <tr style="background:##FFFFFF">
333                                                </cfif>
334                                                <td valign="top" style="font-size:10pt;border-bottom:1px Solid ##CCC;font-family:verdana;">#variables.log[i].time#ms</td>
335                                                <td valign="top" style="font-size:10pt;border-bottom:1px Solid ##CCC;font-family:verdana;">#variables.log[i].type#</td>
336                                                <td valign="top" style="font-size:10pt;border-bottom:1px Solid ##CCC;font-family:verdana;">#variables.log[i].message#</td>
337                                                <td valign="top" align="center" style="font-size:10pt;border-bottom:1px Solid ##CCC;font-family:verdana;">#variables.log[i].occurrence#</td>
338                                        </tr></cfoutput>
339                                </cfloop>
340                        </table>
341                </cfsavecontent>
342               
343                <cfreturn result />
344               
345        </cffunction>
346
347</cfcomponent>
Note: See TracBrowser for help on using the browser.