root / framework / tags / fusebox5RC1 / fuseboxDoFuseaction.cfc

Revision 202, 18.0 kB (checked in by scorfield, 3 years ago)

Fixes #82 by moving all 'special' request variables into request.fusebox and moving the tracing machinery into myFusebox (and therefore deleting the fuseboxTrace component).

Line 
1<!---
2Fusebox Software License
3Version 1.0
4
5Copyright (c) 2003, 2004, 2005, 2006 The Fusebox Corporation. All rights reserved.
6
7Redistribution and use in source and binary forms, with or without modification, are permitted
8provided that the following conditions are met:
9
101. Redistributions of source code must retain the above copyright notice, this list of conditions
11   and the following disclaimer.
12
132. Redistributions in binary form or otherwise encrypted form must reproduce the above copyright
14   notice, this list of conditions and the following disclaimer in the documentation and/or other
15   materials provided with the distribution.
16
173. The end-user documentation included with the redistribution, if any, must include the following
18   acknowledgment:
19
20   "This product includes software developed by the Fusebox Corporation (http://www.fusebox.org/)."
21
22   Alternately, this acknowledgment may appear in the software itself, if and wherever such
23   third-party acknowledgments normally appear.
24
254. The names "Fusebox" and "Fusebox Corporation" must not be used to endorse or promote products
26   derived from this software without prior written (non-electronic) permission. For written
27   permission, please contact fusebox@fusebox.org.
28
295. Products derived from this software may not be called "Fusebox", nor may "Fusebox" appear in
30   their name, without prior written (non-electronic) permission of the Fusebox Corporation. For
31   written permission, please contact fusebox@fusebox.org.
32
33If one or more of the above conditions are violated, then this license is immediately revoked and
34can be re-instated only upon prior written authorization of the Fusebox Corporation.
35
36THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38DISCLAIMED. IN NO EVENT SHALL THE FUSEBOX CORPORATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY
39DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
42STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
43OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44
45-------------------------------------------------------------------------------
46
47This software consists of voluntary contributions made by many individuals on behalf of the
48Fusebox Corporation. For more information on Fusebox, please see <http://www.fusebox.org/>.
49
50--->
51<cfcomponent output="false" hint="I am the representation of the do and fuseaction verbs.">
52       
53        <cffunction name="init" returntype="any" access="public" output="false"
54                                hint="I am the constructor.">
55                <cfargument name="action" type="any" required="true"
56                                        hint="I am the enclosing fuseaction object." />
57                <cfargument name="attributes" type="struct" required="true"
58                                        hint="I am the attributes for this verb." />
59                <cfargument name="children" type="any" required="true"
60                                        hint="I am the XML representation of any children this verb has." />
61                <cfargument name="verb" type="string" required="true"
62                                        hint="I am the name of this verb." />
63                                       
64                <cfset var nAttrs = 1 />
65               
66                <cfset variables.action = arguments.action />
67                <cfset variables.attributes = structNew() />
68                <cfset variables.children = arguments.children />
69                <cfset variables.numChildren = arrayLen(variables.children) />
70                <cfset variables.verb = arguments.verb />
71               
72                <!---
73                        validate the attributes:
74                        action - required
75                        append - boolean - optional
76                        prepend - boolean - optional
77                        overwrite - boolean - optional
78                        contentvariable - optional
79                --->
80                <cfif structKeyExists(arguments.attributes,"action")>
81                        <cfset variables.attributes.action = arguments.attributes.action />
82                <cfelse>
83                        <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
84                                        message="Required attribute is missing"
85                                        detail="The attribute 'action' is required, for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
86                </cfif>
87                <cfif variables.verb is "fuseaction" and listLen(variables.attributes.action,".") neq 2>
88                        <!--- illegal: there is no circuit associated with a (global) action --->
89                        <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
90                                        message="Attribute has invalid value"
91                                        detail="The attribute 'action' must be a fully-qualified fuseaction, for a 'fuseaction' verb in a global pre/post process." />
92                </cfif>         
93               
94                <cfif structKeyExists(arguments.attributes,"append")>
95                        <cfset variables.attributes.append = arguments.attributes.append />
96                        <cfset nAttrs = nAttrs + 1 />
97                        <cfif listFind("true,false",variables.attributes.append) eq 0>
98                                <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
99                                                message="Attribute has invalid value"
100                                                detail="The attribute 'append' must either be ""true"" or ""false"", for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
101                        </cfif>
102                        <cfif not structKeyExists(arguments.attributes,"contentvariable")>
103                                <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
104                                                message="Required attribute is missing"
105                                                detail="The attribute 'contentvariable' is required when the attribute 'append' is present, for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
106                        </cfif>
107                <cfelse>
108                        <cfset variables.attributes.append = false />
109                </cfif>
110
111                <cfif structKeyExists(arguments.attributes,"prepend")>
112                        <cfset variables.attributes.prepend = arguments.attributes.prepend />
113                        <cfset nAttrs = nAttrs + 1 />
114                        <cfif listFind("true,false",variables.attributes.prepend) eq 0>
115                                <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
116                                                message="Attribute has invalid value"
117                                                detail="The attribute 'prepend' must either be ""true"" or ""false"", for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
118                        </cfif>
119                        <cfif not structKeyExists(arguments.attributes,"contentvariable")>
120                                <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
121                                                message="Required attribute is missing"
122                                                detail="The attribute 'contentvariable' is required when the attribute 'append' is present, for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
123                        </cfif>
124                <cfelse>
125                        <cfset variables.attributes.prepend = false />
126                </cfif>
127
128                <cfif structKeyExists(arguments.attributes,"overwrite")>
129                        <cfset variables.attributes.overwrite = arguments.attributes.overwrite />
130                        <cfset nAttrs = nAttrs + 1 />
131                        <cfif listFind("true,false",variables.attributes.overwrite) eq 0>
132                                <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
133                                                message="Attribute has invalid value"
134                                                detail="The attribute 'overwrite' must either be ""true"" or ""false"", for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
135                        </cfif>
136                        <cfif not structKeyExists(arguments.attributes,"contentvariable")>
137                                <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
138                                                message="Required attribute is missing"
139                                                detail="The attribute 'contentvariable' is required when the attribute 'append' is present, for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
140                        </cfif>
141                <cfelse>
142                        <cfset variables.attributes.overwrite = true />
143                </cfif>
144
145                <cfif structKeyExists(arguments.attributes,"contentvariable")>
146                        <cfset variables.attributes.contentvariable = arguments.attributes.contentvariable />
147                        <cfset nAttrs = nAttrs + 1 />
148                </cfif>
149
150                <cfif variables.action.getCircuit().getApplication().strictMode and structCount(arguments.attributes) neq nAttrs>
151                        <cfthrow type="fusebox.badGrammar.unexpectedAttributes"
152                                        message="Unexpected attributes"
153                                        detail="Unexpected attributes were found in a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
154                </cfif>
155               
156                <cfreturn this />
157               
158        </cffunction>
159       
160        <cffunction name="compile" returntype="void" access="public" output="false"
161                                hint="I compile this do/fuseaction verb.">
162                <cfargument name="writer" type="any" required="false"
163                                        hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
164
165                <cfset var i = 0 />
166                <cfset var n = 0 />
167                <cfset var app = variables.action.getCircuit().getApplication() />
168                <cfset var plugins = app.pluginPhases />
169                <cfset var c = "" />
170                <cfset var f = "" />
171                <cfset var cDotF = "" />
172                <cfset var old_c = "" />
173                <cfset var old_p = "" />
174                <cfset var circuits = app.circuits />
175                <cfset var needTryOnFuseaction = false />
176
177                <cfif listLen(variables.attributes.action,".") eq 2>
178                        <!--- action is a circuit.fuseaction pair somewhere --->
179                        <cfset c = listFirst(variables.attributes.action,".") />
180                        <cfset f = listLast(variables.attributes.action,".") />
181                        <cfset cDotF = variables.attributes.action />
182                <cfelse>
183                        <cfset c = variables.action.getCircuit().getAlias() />
184                        <cfset f = variables.attributes.action />
185                        <cfset cDotF = c & "." & f />
186                </cfif>
187               
188                <cfif structKeyExists(request.__fusebox.fuseactionsDone,cDotF)>
189                        <cfthrow type="fusebox.badGrammar.recursiveDo"
190                                        message="Recursive do is illegal"
191                                        detail="An attempt was made to compile a fuseaction '#cDotF#' that is already being compiled, in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
192                </cfif>
193                <cfset request.__fusebox.fuseactionsDone[cDotF] = true />
194               
195                <cfset arguments.writer.rawPrintln('<!--- #variables.verb# action="#variables.attributes.action#" --->') />
196                <cfif app.debug>
197                        <cfset arguments.writer.rawPrintln('<' & 'cfset myFusebox.trace("Runtime","&lt;#variables.verb# action=""#variables.attributes.action#""/&gt;") >') />
198                </cfif>
199                <cfset old_c = arguments.writer.setCircuit(c) />
200                <cfset old_f = arguments.writer.setFuseaction(f) />
201               
202                <cfif structKeyExists(plugins,"fuseactionException") and
203                                arrayLen(plugins["fuseactionException"]) gt 0 and
204                                not request.__fusebox.SuppressPlugins>
205                        <cfset needTryOnFuseaction = true />
206                        <cfset arguments.writer.rawPrintln("<cftry>") />
207                </cfif>
208               
209                <cfif structKeyExists(plugins,"preFuseaction")>
210                        <cfset n = arrayLen(plugins["preFuseaction"]) />
211                        <cfloop from="1" to="#n#" index="i">
212                                <cfset plugins["preFuseaction"][i].compile(arguments.writer) />
213                        </cfloop>
214                </cfif>
215               
216                <cfif variables.numChildren gt 0>
217                        <cfset enterStackFrame(arguments.writer) />
218                </cfif>
219               
220                <cfif structKeyExists(variables.attributes,"contentvariable")>
221                        <cfif not variables.attributes.overwrite>
222                                <cfset arguments.writer.println('<cfif not isDefined("#variables.attributes.contentvariable#")>') />
223                        </cfif>
224                        <cfif variables.attributes.append or variables.attributes.prepend>
225                                <cfset arguments.writer.println('<cfparam name="#variables.attributes.contentvariable#" default="">') />
226                        </cfif>
227                        <cfset arguments.writer.println('<cfsavecontent variable="#variables.attributes.contentvariable#">') />
228                        <cfif variables.attributes.append>
229                                <cfset arguments.writer.println('<' & 'cfoutput>###variables.attributes.contentvariable###</' & 'cfoutput>') />
230                        </cfif>
231                </cfif>
232
233                <cfif listLen(variables.attributes.action,".") eq 2>
234
235                        <cfif not structKeyExists(circuits,c)>
236                                <cfthrow type="fusebox.undefinedCircuit"
237                                                message="undefined Circuit"
238                                                detail="You specified a Circuit of #c# which is not defined." />
239                        </cfif>
240                        <cfif not structKeyExists(circuits[c].fuseactions,f)>
241                                <cfthrow type="fusebox.undefinedFuseaction"
242                                                message="undefined Fuseaction"
243                                                detail="You specified a Fuseaction of #f# which is not defined in Circuit #c#." />
244                        </cfif>
245                        <!--- if not in the same circuit, check access is not private --->
246                        <cfif c is not variables.action.getCircuit().getAlias()>
247                                <cfif circuits[c].fuseactions[f].getAccess() is "private">
248                                        <cfthrow type="fusebox.invalidAccessModifier"
249                                                        message="invalid access modifier"
250                                                        detail="The fuseaction '#c#.#f#' has an access modifier of private and can only be called from within its own circuit. Use an access modifier of internal or public to make it available outside its immediate circuit.">
251                                </cfif>
252                        </cfif>
253
254                        <cfset variables.action.getCircuit().getApplication().compile(arguments.writer,c,f) />
255
256                <cfelse>
257
258                        <!--- action is a fuseaction in this same circuit --->
259                        <cfif not structKeyExists(variables.action.getCircuit().fuseactions,f)>
260                                <cfthrow type="fusebox.undefinedFuseaction"
261                                                message="undefined Fuseaction"
262                                                detail="You specified a Fuseaction of #f# which is not defined in Circuit #c#." />
263                        </cfif>
264
265                        <cfset variables.action.getCircuit().compile(arguments.writer,f) />
266
267                </cfif>
268               
269                <cfif structKeyExists(variables.attributes,"contentvariable")>
270                        <cfif variables.attributes.prepend>
271                                <cfset arguments.writer.println('<' & 'cfoutput>###variables.attributes.contentvariable###</' & 'cfoutput>') />
272                        </cfif>
273                        <cfset arguments.writer.println('</cfsavecontent>') />
274                        <cfif not variables.attributes.overwrite>
275                                <cfset arguments.writer.println('</cfif>') />
276                        </cfif>
277                </cfif>
278
279                <cfif variables.numChildren gt 0>
280                        <cfset leaveStackFrame(arguments.writer) />
281                </cfif>
282               
283                <cfif structKeyExists(plugins,"postFuseaction")>
284                        <cfset n = arrayLen(plugins["postFuseaction"]) />
285                        <cfloop from="1" to="#n#" index="i">
286                                <cfset plugins["postFuseaction"][i].compile(arguments.writer) />
287                        </cfloop>
288                </cfif>
289
290                <cfif needTryOnFuseaction>
291                        <cfset n = arrayLen(plugins["fuseactionException"]) />
292                        <cfloop from="1" to="#n#" index="i">
293                                <cfset plugins["fuseactionException"][i].compile(arguments.writer) />
294                        </cfloop>
295                        <cfset arguments.writer.rawPrintln("</cftry>") />
296                </cfif>
297
298                <cfset arguments.writer.setFuseaction(old_f) />
299                <cfset arguments.writer.setCircuit(old_c) />
300
301                <cfset structDelete(request.__fusebox.fuseactionsDone,cDotF) />
302               
303        </cffunction>
304       
305        <cffunction name="enterStackFrame" returntype="void" access="private" output="false"
306                                hint="I generate code to create a new stack frame and push the scoped variables.">
307                <cfargument name="writer" type="any" required="false"
308                                        hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
309               
310                <cfset var i = 0 />
311                <cfset var child = 0 />
312                <cfset var match1 = 0 />
313                <cfset var match2 = 0 />
314                <cfset var nameLen = 0 />
315               
316                <cfset arguments.writer.rawPrintln('<cfset myFusebox.enterStackFrame() >') />
317                <cfloop from="1" to="#variables.numChildren#" index="i">
318                        <cfset child = variables.children[i] />
319                        <!--- validate the child: it must be <parameter> and have both name= and value= --->
320                        <cfif child.xmlName is "parameter">
321                                <cfif not structKeyExists(child.xmlAttributes,"name")>
322                                        <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
323                                                        message="Required attribute is missing"
324                                                        detail="The attribute 'name' is required, for a 'parameter' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
325                                </cfif>
326                                <cfset match1 = REFind("[A-Za-z0-9_]*",child.xmlAttributes.name,1,true) />
327                                <cfset match2 = REFind("[A-Za-z0-9_]*\.[A-Za-z0-9_]*",child.xmlAttributes.name,1,true) />
328                                <cfset nameLen = len(child.xmlAttributes.name) />
329                                <cfif match1.pos[1] eq 1 and match1.len[1] eq nameLen>
330                                        <!--- simple varname: patch up XML to make leaveStackFrame() simpler --->
331                                        <cfset child.xmlAttributes.name = "variables." & child.xmlAttributes.name />
332                                <cfelseif match2.pos[1] eq 1 and match2.len[1] eq nameLen>
333                                        <!--- scoped varname.varname: nothing to patch up --->
334                                <cfelse>
335                                        <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
336                                                        message="Attribute has invalid value"
337                                                        detail="The attribute 'name' must be a simple variable name, optionally qualified by a scope name, for a 'parameter' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
338                                </cfif>
339                                <cfset arguments.writer.rawPrintln('<' & 'cfif isDefined("#child.xmlAttributes.name#")><' &
340                                                        'cfset myFusebox.stack["#child.xmlAttributes.name#"] = #child.xmlAttributes.name# ></' & 'cfif>') />
341                                <cfif structKeyExists(child.xmlAttributes,"value")>
342                                        <cfset arguments.writer.rawPrintln('<' & 'cfset #child.xmlAttributes.name# = "#child.xmlAttributes.value#" >') />
343                                </cfif>
344                        <cfelse>
345                                <cfthrow type="fusebox.badGrammar.illegalVerb"
346                                                message="Illegal verb encountered"
347                                                detail="The '#child.xmlName#' verb is illegal inside a 'do' verb, in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
348                        </cfif>
349                </cfloop>
350               
351        </cffunction>
352       
353        <cffunction name="leaveStackFrame" returntype="void" access="private" output="false"
354                                hint="I generate code to pop the scoped variables and drop the stack frame.">
355                <cfargument name="writer" type="any" required="false"
356                                        hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
357               
358                <cfset var i = 0 />
359                <cfset var child = 0 />
360                <cfset var scope = "" />
361                <cfset var qName = "" />
362               
363                <cfloop from="#variables.numChildren#" to="1" step="-1" index="i">
364                        <cfset child = variables.children[i] />
365                        <cfset arguments.writer.rawPrintln('<' & 'cfif structKeyExists(myFusebox.stack,"#child.xmlAttributes.name#")><' &
366                                                'cfset #child.xmlAttributes.name# = myFusebox.stack["#child.xmlAttributes.name#"] ></' & 'cfif>') />
367                        <cfset scope = listFirst(child.xmlAttributes.name,".") />
368                        <cfset qName = listRest(child.xmlAttributes.name,".") />
369                        <cfset arguments.writer.rawPrintln('<' & 'cfif structKeyExists(myFusebox.stack,"#child.xmlAttributes.name#")><' &
370                                                        'cfset #child.xmlAttributes.name# = myFusebox.stack["#child.xmlAttributes.name#"] ><' &
371                                                        'cfelse><' &
372                                                        'cfset structDelete(#scope#,"#qName#")></' & 'cfif>') />
373                </cfloop>
374                <cfset arguments.writer.rawPrintln('<cfset myFusebox.leaveStackFrame() >') />
375               
376        </cffunction>
377       
378</cfcomponent>
Note: See TracBrowser for help on using the browser.