root / framework / trunk / corefiles / fuseboxDoFuseaction.cfc

Revision 674, 16.4 kB (checked in by scorfield, 1 year ago)

Addresses #310 by moving everything around! :)

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 output="false" hint="I am the representation of the do and fuseaction verbs.">
17       
18        <cffunction name="init" returntype="any" access="public" output="false"
19                                hint="I am the constructor.">
20                <cfargument name="action" type="any" required="true"
21                                        hint="I am the enclosing fuseaction object." />
22                <cfargument name="attributes" type="struct" required="true"
23                                        hint="I am the attributes for this verb." />
24                <cfargument name="children" type="any" required="true"
25                                        hint="I am the XML representation of any children this verb has." />
26                <cfargument name="verb" type="string" required="true"
27                                        hint="I am the name of this verb." />
28                                       
29                <cfset var nAttrs = 1 />
30               
31                <cfset variables.action = arguments.action />
32                <cfset variables.attributes = structNew() />
33                <cfset variables.children = arguments.children />
34                <cfset variables.numChildren = arrayLen(variables.children) />
35                <cfset variables.verb = arguments.verb />
36               
37                <!---
38                        validate the attributes:
39                        action - required
40                        append - boolean - optional
41                        prepend - boolean - optional
42                        overwrite - boolean - optional
43                        contentvariable - optional
44                --->
45                <cfif structKeyExists(arguments.attributes,"action")>
46                        <cfset variables.attributes.action = arguments.attributes.action />
47                <cfelse>
48                        <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
49                                        message="Required attribute is missing"
50                                        detail="The attribute 'action' is required, for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
51                </cfif>
52                <cfif variables.verb is "fuseaction" and listLen(variables.attributes.action,".") lt 2>
53                        <!--- illegal: there is no circuit associated with a (global) action --->
54                        <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
55                                        message="Attribute has invalid value"
56                                        detail="The attribute 'action' must be a fully-qualified fuseaction, for a 'fuseaction' verb in a global pre/post process." />
57                </cfif>         
58               
59                <cfif structKeyExists(arguments.attributes,"append")>
60                        <cfset variables.attributes.append = arguments.attributes.append />
61                        <cfset nAttrs = nAttrs + 1 />
62                        <cfif listFind("true,false,yes,no",variables.attributes.append) eq 0>
63                                <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
64                                                message="Attribute has invalid value"
65                                                detail="The attribute 'append' must either be ""true"" or ""false"", for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
66                        </cfif>
67                        <cfif not structKeyExists(arguments.attributes,"contentvariable")>
68                                <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
69                                                message="Required attribute is missing"
70                                                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()#." />
71                        </cfif>
72                <cfelse>
73                        <cfset variables.attributes.append = false />
74                </cfif>
75
76                <cfif structKeyExists(arguments.attributes,"prepend")>
77                        <cfset variables.attributes.prepend = arguments.attributes.prepend />
78                        <cfset nAttrs = nAttrs + 1 />
79                        <cfif listFind("true,false,yes,no",variables.attributes.prepend) eq 0>
80                                <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
81                                                message="Attribute has invalid value"
82                                                detail="The attribute 'prepend' must either be ""true"" or ""false"", for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
83                        </cfif>
84                        <cfif not structKeyExists(arguments.attributes,"contentvariable")>
85                                <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
86                                                message="Required attribute is missing"
87                                                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()#." />
88                        </cfif>
89                <cfelse>
90                        <cfset variables.attributes.prepend = false />
91                </cfif>
92
93                <cfif structKeyExists(arguments.attributes,"overwrite")>
94                        <cfset variables.attributes.overwrite = arguments.attributes.overwrite />
95                        <cfset nAttrs = nAttrs + 1 />
96                        <cfif listFind("true,false,yes,no",variables.attributes.overwrite) eq 0>
97                                <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
98                                                message="Attribute has invalid value"
99                                                detail="The attribute 'overwrite' must either be ""true"" or ""false"", for a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
100                        </cfif>
101                        <cfif not structKeyExists(arguments.attributes,"contentvariable")>
102                                <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
103                                                message="Required attribute is missing"
104                                                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()#." />
105                        </cfif>
106                <cfelse>
107                        <cfset variables.attributes.overwrite = true />
108                </cfif>
109
110                <cfif structKeyExists(arguments.attributes,"contentvariable")>
111                        <cfset variables.attributes.contentvariable = arguments.attributes.contentvariable />
112                        <cfset nAttrs = nAttrs + 1 />
113                </cfif>
114
115                <cfif variables.action.getCircuit().getApplication().strictMode and structCount(arguments.attributes) neq nAttrs>
116                        <cfthrow type="fusebox.badGrammar.unexpectedAttributes"
117                                        message="Unexpected attributes"
118                                        detail="Unexpected attributes were found in a '#variables.verb#' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
119                </cfif>
120               
121                <cfreturn this />
122               
123        </cffunction>
124       
125        <cffunction name="compile" returntype="void" access="public" output="false"
126                                hint="I compile this do/fuseaction verb.">
127                <cfargument name="writer" type="any" required="false"
128                                        hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
129
130                <cfset var i = 0 />
131                <cfset var n = 0 />
132                <cfset var app = variables.action.getCircuit().getApplication() />
133                <cfset var plugins = app.pluginPhases />
134                <cfset var c = "" />
135                <cfset var f = "" />
136                <cfset var cDotF = "" />
137                <cfset var old_c = "" />
138                <cfset var old_f = "" />
139                <cfset var circuits = app.circuits />
140                <cfset var needTryOnFuseaction = false />
141
142                <cfif listLen(variables.attributes.action,".") gte 2>
143                        <!--- action is a circuit.fuseaction pair somewhere --->
144                        <cfset f = listLast(variables.attributes.action,".") />
145                        <cfset c = left(variables.attributes.action,len(variables.attributes.action)-len(f)-1) />
146                        <cfset cDotF = variables.attributes.action />
147                <cfelse>
148                        <cfset c = variables.action.getCircuit().getAlias() />
149                        <cfset f = variables.attributes.action />
150                        <cfset cDotF = c & "." & f />
151                </cfif>
152               
153                <cfif structKeyExists(request.__fusebox.fuseactionsDone,cDotF)>
154                        <cfthrow type="fusebox.badGrammar.recursiveDo"
155                                        message="Recursive do is illegal"
156                                        detail="An attempt was made to compile a fuseaction '#cDotF#' that is already being compiled, in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
157                </cfif>
158                <cfset request.__fusebox.fuseactionsDone[cDotF] = true />
159               
160                <cfset arguments.writer.rawPrintln('<!--- #variables.verb# action="#variables.attributes.action#" --->') />
161                <cfif app.debug>
162                        <cfset arguments.writer.rawPrintln('<' & 'cfset myFusebox.trace("Runtime","&lt;#variables.verb# action=""#variables.attributes.action#""/&gt;") >') />
163                </cfif>
164                <cfset old_c = arguments.writer.setCircuit(c) />
165                <cfset old_f = arguments.writer.setFuseaction(f) />
166               
167                <cfif structKeyExists(plugins,"fuseactionException") and
168                                arrayLen(plugins["fuseactionException"]) gt 0 and
169                                not request.__fusebox.SuppressPlugins>
170                        <cfset needTryOnFuseaction = true />
171                        <cfset arguments.writer.rawPrintln("<cftry>") />
172                </cfif>
173               
174                <cfif structKeyExists(plugins,"preFuseaction")>
175                        <cfset n = arrayLen(plugins["preFuseaction"]) />
176                        <cfloop from="1" to="#n#" index="i">
177                                <cfset plugins["preFuseaction"][i].compile(arguments.writer) />
178                        </cfloop>
179                </cfif>
180               
181                <cfif variables.numChildren gt 0>
182                        <cfset enterStackFrame(arguments.writer) />
183                </cfif>
184               
185                <cfif structKeyExists(variables.attributes,"contentvariable")>
186                        <cfif not variables.attributes.overwrite>
187                                <cfset arguments.writer.println('<cfif not isDefined("#variables.attributes.contentvariable#")>') />
188                        </cfif>
189                        <cfif variables.attributes.append or variables.attributes.prepend>
190                                <cfset arguments.writer.println('<cfparam name="#variables.attributes.contentvariable#" default="">') />
191                        </cfif>
192                        <cfset arguments.writer.println('<cfsavecontent variable="#variables.attributes.contentvariable#">') />
193                        <cfif variables.attributes.append>
194                                <cfset arguments.writer.println('<' & 'cfoutput>###variables.attributes.contentvariable###</' & 'cfoutput>') />
195                        </cfif>
196                </cfif>
197
198                <cfif listLen(variables.attributes.action,".") gte 2>
199
200                        <cfif structKeyExists(circuits,c)>
201
202                                <cfif structKeyExists(circuits[c].fuseactions,f)>
203
204                                        <!--- if not in the same circuit, check access is not private --->
205                                        <cfif c is not variables.action.getCircuit().getAlias()>
206
207                                                <cfif circuits[c].fuseactions[f].getAccess() is "private">
208
209                                                        <cfthrow type="fusebox.invalidAccessModifier"
210                                                                        message="invalid access modifier"
211                                                                        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.">
212
213                                                </cfif>
214
215                                        </cfif>
216                                       
217                                <!--- ticket 309 - remove fuseaction check prior to compile so that implicit circuits work --->
218                               
219                                </cfif>
220
221                        <cfelseif not variables.action.getCircuit().getApplication().allowImplicitCircuits>
222
223                                <cfthrow type="fusebox.undefinedCircuit"
224                                                message="undefined Circuit"
225                                                detail="You specified a Circuit of #c# which is not defined." />
226
227                        </cfif>
228
229                        <cfset variables.action.getCircuit().getApplication().compile(arguments.writer,c,f) />
230
231                <cfelse>
232
233                        <!--- action is a fuseaction in this same circuit --->
234                        <cfif not structKeyExists(variables.action.getCircuit().fuseactions,f)>
235                                <cfthrow type="fusebox.undefinedFuseaction"
236                                                message="undefined Fuseaction"
237                                                detail="You specified a Fuseaction of #f# which is not defined in Circuit #c#." />
238                        </cfif>
239
240                        <cfset variables.action.getCircuit().compile(arguments.writer,f) />
241
242                </cfif>
243               
244                <cfif structKeyExists(variables.attributes,"contentvariable")>
245                        <cfif variables.attributes.prepend>
246                                <cfset arguments.writer.println('<' & 'cfoutput>###variables.attributes.contentvariable###</' & 'cfoutput>') />
247                        </cfif>
248                        <cfset arguments.writer.println('</cfsavecontent>') />
249                        <cfif not variables.attributes.overwrite>
250                                <cfset arguments.writer.println('</cfif>') />
251                        </cfif>
252                </cfif>
253
254                <cfif variables.numChildren gt 0>
255                        <cfset leaveStackFrame(arguments.writer) />
256                </cfif>
257               
258                <cfif structKeyExists(plugins,"postFuseaction")>
259                        <cfset n = arrayLen(plugins["postFuseaction"]) />
260                        <cfloop from="1" to="#n#" index="i">
261                                <cfset plugins["postFuseaction"][i].compile(arguments.writer) />
262                        </cfloop>
263                </cfif>
264
265                <cfif needTryOnFuseaction>
266                        <cfset n = arrayLen(plugins["fuseactionException"]) />
267                        <cfloop from="1" to="#n#" index="i">
268                                <cfset plugins["fuseactionException"][i].compile(arguments.writer) />
269                        </cfloop>
270                        <cfset arguments.writer.rawPrintln("</cftry>") />
271                </cfif>
272
273                <cfset arguments.writer.setFuseaction(old_f) />
274                <cfset arguments.writer.setCircuit(old_c) />
275
276                <cfset structDelete(request.__fusebox.fuseactionsDone,cDotF) />
277               
278        </cffunction>
279       
280        <cffunction name="enterStackFrame" returntype="void" access="private" output="false"
281                                hint="I generate code to create a new stack frame and push the scoped variables.">
282                <cfargument name="writer" type="any" required="false"
283                                        hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
284               
285                <cfset var i = 0 />
286                <cfset var child = 0 />
287                <cfset var match1 = 0 />
288                <cfset var match2 = 0 />
289                <cfset var nameLen = 0 />
290               
291                <cfset arguments.writer.rawPrintln('<cfset myFusebox.enterStackFrame() >') />
292                <cfloop from="1" to="#variables.numChildren#" index="i">
293                        <cfset child = variables.children[i] />
294                        <!--- validate the child: it must be <parameter> and have both name= and value= --->
295                        <cfif child.xmlName is "parameter">
296                                <cfif not structKeyExists(child.xmlAttributes,"name")>
297                                        <cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
298                                                        message="Required attribute is missing"
299                                                        detail="The attribute 'name' is required, for a 'parameter' verb in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
300                                </cfif>
301                                <cfset match1 = REFind("[A-Za-z0-9_]*",child.xmlAttributes.name,1,true) />
302                                <cfset match2 = REFind("[A-Za-z0-9_]*\.[A-Za-z0-9_]*",child.xmlAttributes.name,1,true) />
303                                <cfset nameLen = len(child.xmlAttributes.name) />
304                                <cfif match1.pos[1] eq 1 and match1.len[1] eq nameLen>
305                                        <!--- simple varname: patch up XML to make leaveStackFrame() simpler --->
306                                        <cfset child.xmlAttributes.name = "variables." & child.xmlAttributes.name />
307                                <cfelseif match2.pos[1] eq 1 and match2.len[1] eq nameLen>
308                                        <!--- scoped varname.varname: nothing to patch up --->
309                                <cfelse>
310                                        <cfthrow type="fusebox.badGrammar.invalidAttributeValue"
311                                                        message="Attribute has invalid value"
312                                                        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()#." />
313                                </cfif>
314                                <cfset arguments.writer.rawPrintln('<' & 'cfif isDefined("#child.xmlAttributes.name#")><' &
315                                                        'cfset myFusebox.stack["#child.xmlAttributes.name#"] = #child.xmlAttributes.name# ></' & 'cfif>') />
316                                <cfif structKeyExists(child.xmlAttributes,"value")>
317                                        <cfset arguments.writer.rawPrintln('<' & 'cfset #child.xmlAttributes.name# = "#child.xmlAttributes.value#" >') />
318                                </cfif>
319                        <cfelse>
320                                <cfthrow type="fusebox.badGrammar.illegalVerb"
321                                                message="Illegal verb encountered"
322                                                detail="The '#child.xmlName#' verb is illegal inside a 'do' verb, in fuseaction #variables.action.getCircuit().getAlias()#.#variables.action.getName()#." />
323                        </cfif>
324                </cfloop>
325               
326        </cffunction>
327       
328        <cffunction name="leaveStackFrame" returntype="void" access="private" output="false"
329                                hint="I generate code to pop the scoped variables and drop the stack frame.">
330                <cfargument name="writer" type="any" required="false"
331                                        hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
332               
333                <cfset var i = 0 />
334                <cfset var child = 0 />
335                <cfset var scope = "" />
336                <cfset var qName = "" />
337               
338                <cfloop from="#variables.numChildren#" to="1" step="-1" index="i">
339                        <cfset child = variables.children[i] />
340                        <cfset arguments.writer.rawPrintln('<' & 'cfif structKeyExists(myFusebox.stack,"#child.xmlAttributes.name#")><' &
341                                                'cfset #child.xmlAttributes.name# = myFusebox.stack["#child.xmlAttributes.name#"] ></' & 'cfif>') />
342                        <cfset scope = listFirst(child.xmlAttributes.name,".") />
343                        <cfset qName = listRest(child.xmlAttributes.name,".") />
344                        <cfset arguments.writer.rawPrintln('<' & 'cfif structKeyExists(myFusebox.stack,"#child.xmlAttributes.name#")><' &
345                                                        'cfset #child.xmlAttributes.name# = myFusebox.stack["#child.xmlAttributes.name#"] ><' &
346                                                        'cfelse><' &
347                                                        'cfset structDelete(#scope#,"#qName#")></' & 'cfif>') />
348                </cfloop>
349                <cfset arguments.writer.rawPrintln('<cfset myFusebox.leaveStackFrame() >') />
350               
351        </cffunction>
352
353        <cffunction name="getNamespace" returntype="string" access="public" output="false"
354                                hint="I return the namespace for this verb (which will be empty).">
355
356                <cfreturn "" />
357
358        </cffunction>   
359       
360        <cffunction name="getVerb" returntype="string" access="public" output="false">
361
362                <cfreturn variables.verb />
363
364        </cffunction>
365       
366</cfcomponent>
Note: See TracBrowser for help on using the browser.