root / phpframework / trunk / fuseboxDoFuseaction.php

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