root/trunk/trax/vendor/trax/action_controller.php

Revision 317, 56.3 KB (checked in by john, 3 years ago)

fixed a render bug render_performed = false when render as string

  • Property svn:keywords set to Id
Line 
1<?php
2/**
3 *  File containing ActionController class
4 *
5 *  (PHP 5)
6 *
7 *  @package PHPonTrax
8 *  @version $Id$
9 *  @copyright (c) 2005 John Peterson
10 *
11 *  Permission is hereby granted, free of charge, to any person obtaining
12 *  a copy of this software and associated documentation files (the
13 *  "Software"), to deal in the Software without restriction, including
14 *  without limitation the rights to use, copy, modify, merge, publish,
15 *  distribute, sublicense, and/or sell copies of the Software, and to
16 *  permit persons to whom the Software is furnished to do so, subject to
17 *  the following conditions:
18 *
19 *  The above copyright notice and this permission notice shall be
20 *  included in all copies or substantial portions of the Software.
21 *
22 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/**
32 *  Action controller
33 *
34 *  <p>The ActionController base class operates as follows:</p>
35 *  <ol>
36 *    <li>Accept a URL as input</li>
37 *    <li>Translate the URL into a controller and action</li>
38 *    <li>Create the indicated controller object (which is a subclass
39 *      of ActionController) and call its action method</li>
40 *    <li>Render the output of the action method</li>
41 *    <li>Redirect to the next URL</li>
42 *  </ol>
43 *
44 *  For details see the
45 *  {@tutorial PHPonTrax/ActionController.cls class tutorial}
46 */
47class ActionController {
48
49    /**
50     *  Name of the controller (without the _controller.php)
51     *
52     *  Set by {@link recognize_route()} by parsing the URL and the
53     *  routes in {@link routes.php}.  The value of this string is set
54     *  before any attempt is made to find the file containing the
55     *  controller.
56     *  @var string
57     */
58    protected $controller;
59
60    /**
61     *  Name of the action method in the controller class
62     *
63     *  Set by {@link recognize_route()}
64     *  @var string
65     */
66    protected $action;
67
68    /**
69     *  Path to add to other filesystem paths
70     *
71     *  Set by {@link recognize_route()}
72     *  @var string
73     */
74    private $added_path = '';
75
76    /**
77     *  Filesystem path to ../app/controllers/ directory
78     *
79     *  Set by {@link recognize_route()}
80     *  @var string
81     */
82    private $controllers_path;
83
84    /**
85     *  Filesystem path to ../app/helpers/<i>extras</i> directory
86     *
87     *  Set by {@link recognize_route()}, {@link set_paths()}
88     *  @var string
89     */
90    private $helpers_path;
91
92    /**
93     *  Filesystem path to ../app/helpers/ directory
94     *
95     *  Set by {@link recognize_route()}
96     *  @var string
97     */
98    private $helpers_base_path;
99
100    /**
101     *  Filesystem path to ../app/views/layouts/<i>extras</i> directory
102     *
103     *  Set by {@link recognize_route()}, {@link set_paths()}
104     *  @var string
105     */
106    private $layouts_path;
107
108    /**
109     *  Filesystem path to ../app/views/layouts/ directory
110     *
111     *  Set by {@link recognize_route()}
112     *  @var string
113     */
114    private $layouts_base_path;
115
116    /**
117     *  User's URL in components
118     *
119     *  Contains user's URL stripped of TRAX_URL_PREFIX and leading
120     *  and trailing slashes, then exploded into an array on slash
121     *  boundaries.
122     *  @var string[]
123     */
124    private $url_path;
125
126    /**
127     *  Filesystem path to the controllername_helper.php file
128     *
129     *  Set by {@link recognize_route()}
130     *  @var string
131     */
132    private $helper_file;
133
134    /**
135     *  Filesystem path to application.php file
136     *
137     *  Set by {@link recognize_route()}
138     *  @see $controller_file
139     *  @var string
140     */
141    private $application_controller_file;
142
143    /**
144     *  Filesystem path to application_helper.php file
145     *
146     *  Set by {@link recognize_route()}
147     *  @var string
148     */
149    private $application_helper_file;
150
151    /**
152     *  URL recognized, paths resoved, controller file found
153     *
154     *  Set by {@link recognize_route()}
155     *  @var boolean
156     */
157    private $loaded = false;
158
159    /**
160     *  Whether a Router object was loaded
161     *
162     *  @var boolean
163     *  <ul>
164     *    <li>true => $router points to the Router object</li>
165     *    <li>false => no Router object exists</li>
166     *  </ul>
167     *  @todo <b>FIXME:</b> No declaration of $router so no place to hang
168     *    its documentation.
169     */
170    private $router_loaded = false;
171
172    /**
173     *  List of additional helper files for this controller object
174     *
175     *  Set by {@link add_helper()}
176     *  @var string[]
177     */
178    private $helpers = array();
179
180    /**
181     *  List of filters to execute before calling action method
182     *
183     *  Set by {@link add_before_filters()
184     *  @var string[]
185     */
186    public $before_filters = array();
187
188    public $before_filter_options = array();
189
190    /**
191     *  List of filters to execute after calling action method
192     *
193     *  Set by {@link add_after_filters()
194     *  @var string[]
195     */
196    private $after_filters = array();     
197
198    private $after_filter_options = array();
199
200    /**
201     *  @todo Document this attribute
202     */
203    private $render_performed = false;
204
205    /**
206     *  @todo Document this attribute
207     */
208    private $action_called = false;
209
210    /**
211     *  @todo Document this attribute
212     */
213    #protected $before_filter = null;
214
215    /**
216     *  @todo Document this attribute
217     */
218    #protected $after_filter = null;
219
220    /**
221     *  Filesystem path to the PHP program file for this controller
222     *
223     *  Set by {@link recognize_route()}
224     *  @see $application_controller_file
225     *  @var string
226     */
227    public $controller_file;
228
229    /**
230     *  Filesystem path to the view file selected for this action
231     *
232     *  Set by {@link process_route()
233     *  @var string
234     */
235    public $view_file;
236
237    /**
238     *  Filesystem path to the ../app/views/ directory
239     *
240     *  Set by {@link recognize_route()}
241     *  @var string
242     */
243    public $views_path;
244
245    /**
246     *  Class name of the controller
247     *
248     *  Set by {@link recognize_route()}.
249     *  Derived from contents of {@link $controller}.
250     *  @var string
251     */
252    public $controller_class;
253
254    /**
255     *  Instance of the controller class
256     *
257     *  Set by {@link process_route()}
258     *  @var object
259     */
260    public $controller_object;
261
262    /**
263     *  @todo Document this attribute
264     *  @todo <b>FIXME:</b> Not referenced in this class - is it used
265     *        by subclasses?  If so, for what?
266     *  @var string
267     */
268    public $asset_host = null;
269
270    /**
271     *  Render controllers layout
272     *
273     *  Can be overridden in the child controller to false
274     *  @var boolean
275     */
276    public $render_layout = true;
277   
278    /**
279     *  Whether to keep flash message after displaying it
280     *  @var boolean
281     */
282    public $keep_flash = false;
283
284    /**
285     *  Keeps track of open blocks when calling content_for()
286     *  @var array
287     */
288    public $content_for_open_blocks = array();
289
290    /**
291     *  Build a Router object and load routes from config/route.php
292     *  @uses load_router()
293     */
294    function __construct() {
295        if(!isset($this->router) || !is_object($this->router)) {
296            $this->load_router();
297        }
298    }
299
300    /**
301     *  @todo Document this method
302     *  @uses add_after_filter()
303     *  @uses add_before_filter()
304     *  @uses add_helper()
305     */
306    function __set($key, $value) {
307        #if(is_string($value) || is_array($value)) {
308            #error_log("__set($key, $value)");
309        #}
310        if($key == "before_filter") {
311            $this->add_before_filter($value);
312            unset($this->$key);
313        } elseif($key == "after_filter") {
314            $this->add_after_filter($value);
315        } elseif($key == "helper") {
316            $this->add_helper($value);
317        } elseif($key == "render_text") {
318            $this->render_text($value);
319        } elseif($key == "redirect_to") {
320            $this->redirect_to($value);       
321        } elseif($key == "layout") {
322            $this->layout = $value;
323            $this->determine_layout();   
324        } else {
325            $this->$key = $value;
326        }
327    }
328
329    /**
330     *  @todo Document this method
331     *  Implement before_filter(), after_filter(), helper()
332     */
333    function __call($method_name, $parameters) {
334        if(method_exists($this, $method_name)) {
335            #error_log("calling method:{$method_name} - params:".print_r($parameters, true));
336            # If the method exists, just call it
337            $result = call_user_func_array(array($this, $method_name), $parameters);
338        } else {       
339            if($method_name == "before_filter") {
340                $result = call_user_func(array($this, 'add_before_filter'), $parameters);
341            } elseif($method_name == "after_filter") {
342                $result = call_user_func(array($this, 'add_after_filter'), $parameters);
343            } elseif($method_name == "helper") {
344                $result = call_user_func(array($this, 'add_helper'), $parameters);
345            } 
346        }
347        return $result;
348    }
349
350    /**
351     *  Load routes from configuration file config/routes.php
352     *
353     *  Routes are loaded by requiring {@link routes.php} from the
354     *  configuration directory.  The file routes.php contains
355     *  statements of the form "$router->connect(path,params);" where
356     *  (path,params) describes the route being added by the
357     *  statement. Route syntax is described in
358     *  {@tutorial PHPonTrax/Router.cls the Router class tutorial}.
359     *
360     *  @uses Router
361     *  @uses $router
362     *  @uses $router_loaded
363     */
364    function load_router() {
365        $this->router_loaded = false;
366        $router = new Router();
367
368        // Load the routes.
369        require(Trax::$config_path."/routes.php");
370        $this->router = $router;
371        if(is_object($this->router)) {
372            $this->router_loaded = true;
373        }
374    }
375
376    /**
377     *  Convert URL to controller, action and id
378     *
379     *  Parse the URL in
380     *  {@link
381     *  http://www.php.net/manual/en/reserved.variables.php#reserved.variables.server $_SERVER}['REDIRECT_URL']
382     *  into elements.
383     *  Compute filesystem paths to the various components used by the
384     *  URL and store the paths in object private variables.
385     *  Verify that the controller exists.
386     *
387     *  @uses load_router()
388     *  @uses $action
389     *  @uses $application_controller_file
390     *  @uses $controller
391     *  @uses $controller_class
392     *  @uses $controller_file
393     *  @uses $controllers_path
394     *  @uses $helper_file
395     *  @uses $helpers_path
396     *  @uses $id
397     *  @uses $layouts_path
398     *  @uses $loaded
399     *  @uses $router
400     *  @uses $router_loaded
401     *  @uses set_paths()
402     *  @uses $url_path
403     *  @uses $views_path
404     *  @return boolean
405     *  <ul>
406     *    <li>true =>  route recognized, controller found.</li>
407     *    <li>false => failed, route not recognized.</li>
408     *  </ul>
409     */
410    function recognize_route() {
411        if(!$this->router_loaded) {
412            $this->load_router();
413        }
414
415        # current url
416        if(isset($_SERVER['REDIRECT_URL']) && !stristr($_SERVER['REDIRECT_URL'], 'dispatch.php')) {
417            $browser_url = $_SERVER['REDIRECT_URL'];
418        } elseif(isset($_SERVER['REQUEST_URI'])) {
419            $browser_url = strstr($_SERVER['REQUEST_URI'], "?") ?
420                substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], "?")) :
421                $_SERVER['REQUEST_URI'];
422        }
423
424        //error_log('browser url='.$browser_url);
425        # strip off url prefix, if any
426        if(!is_null(Trax::$url_prefix)) {
427            $browser_url = str_replace(Trax::$url_prefix, "", $browser_url);
428        }
429
430        # strip leading slash (if any)
431        if(substr($browser_url, 0, 1) == "/") {
432            $browser_url = substr($browser_url, 1);
433        }
434
435        # strip trailing slash (if any)
436        if(substr($browser_url, -1) == "/") {
437            $browser_url = substr($browser_url, 0, -1);
438        }
439
440        if($browser_url) {
441            $this->url_path = explode("/", $browser_url);
442        } else {
443            $this->url_path = array();
444        }
445
446        if($this->router->routes_count > 0) {
447            $this->controllers_path = Trax::$controllers_path;
448            $this->helpers_path = $this->helpers_base_path = Trax::$helpers_path;
449            $this->application_controller_file = $this->controllers_path . "/application.php";
450            $this->application_helper_file = $this->helpers_path . "/application_helper.php";
451            $this->layouts_path = Trax::$layouts_path;
452            $this->views_path = Trax::$views_path;
453
454            $route = $this->router->find_route($browser_url);
455
456            //  find_route() returns an array if it finds a path that
457            //  matches the URL, null if no match found
458            if(is_array($route)) {
459
460                //  Matching route found.  Try to get
461                //  controller and action from route and URL
462                $this->set_paths();
463                $route_path = explode("/",$route['path']);
464                $route_params = $route['params'];
465
466                //  Find the controller from the route and URL
467                if(is_array($route_params)
468                   && array_key_exists(":controller",$route_params)) {
469
470                    //  ':controller' in route params overrides URL
471                    $this->controller = $route_params[":controller"]; 
472                    if(stristr($route_params[":controller"], "/")) {
473                       
474                    }
475                } elseif(is_array($route_path)
476                         && in_array(":controller",$route_path)
477                         && (count($this->url_path)>0)) {
478
479                    //  Set controller from URL if that field exists
480                    $this->controller = strtolower($this->url_path[array_search(":controller", $route_path)]);
481                }
482                //error_log('controller='.$this->controller);
483
484                //  Find the action from the route and URL
485                if(is_array($route_params)
486                   && array_key_exists(":action",$route_params)) {
487
488                    //  ':action' in route params overrides URL
489                    $this->action = $route_params[':action'];
490                } elseif(is_array($route_path)
491                         && in_array(":action",$route_path)
492                         && array_key_exists(@array_search(":action",
493                                                           $route_path),
494                                             $this->url_path)) {
495
496                    //  Get action from URL if that field exists
497                    $this->action = strtolower($this->url_path[@array_search(":action", $route_path)]);
498                }
499                //error_log('action='.$this->action);
500
501                //  FIXME: RoR uses :name as a keyword parameter, id
502                //  is not treated as a special case.
503                //  Do we want to do the same?
504                if(is_array($route_params)
505                   && array_key_exists(":id",$route_params)) {
506
507                    //  ':id' in route params overrides URL
508                    $id = $route_params[':id'];
509                } elseif(@in_array(":id",$route_path)) {
510                    #print_r($this->url_path);
511                    #print_r($route_path);
512                    #if(count($this->extra_path)) {
513                        #foreach(array_reverse($this->extra_path) as $extra_path) {
514                            #array_unshift($this->url_path, $extra_path);
515                        #}
516                    #}
517                    #print_r($this->url_path);
518
519                    $id = strtolower($this->url_path[@array_search(":id", $route_path)]);
520                }
521                //  For historical reasons, continue to pass id
522                //  in $_REQUEST
523                if($id != "") {
524                    $_REQUEST['id'] = $id;
525                }
526                //error_log('id='.$id);
527
528                $this->views_path .= "/" . $this->controller;
529                $this->controller_file = $this->controllers_path . "/" .  $this->controller . "_controller.php";
530                $this->controller_class = Inflector::camelize(Inflector::demodulize($this->controller)) . "Controller";
531                $this->helper_file = $this->helpers_path . "/" .  $this->controller . "_helper.php"; 
532                # error_log("controller:{$this->controller} - controller_file:{$this->controller_file} - controller_class:{$this->controller_class} - views_path:{$this->views_path}");
533            }
534        }
535
536        if(is_file($this->controller_file)) {
537            $this->loaded = true;
538            return true;
539        } else {
540            $this->loaded = false;
541            return false;
542        }
543    }
544
545    /**
546     *  Parse URL, extract controller and action and execute them
547     *
548     *  @uses $action
549     *  @uses $application_controller_file
550     *  @uses $application_helper_file
551     *  @uses $controller
552     *  @uses $controller_class
553     *  @uses $controller_file
554     *  @uses $controller_object
555     *  @uses determine_layout()
556     *  @uses execute_after_filters()
557     *  @uses $helpers
558     *  @uses $helper_file
559     *  @uses $helpers_base_path
560     *  @uses $keep_flash
561     *  @uses $loaded
562     *  @uses recognize_route()
563     *  @uses raise()
564     *  @uses ScaffoldController
565     *  @uses Session::unset_var()
566     *  @uses $view_file
567     *  @uses $views_path
568     *  @return boolean true
569     */
570    function process_route() {
571   
572        # First try to load the routes and setup the paths to everything
573        if(!$this->loaded) {
574            if(!$this->recognize_route()) {
575                $this->raise("Failed to load any defined routes",
576                 "Controller ".$this->controller." not found",
577                 "404");
578            }
579        }
580        //error_log('process_route(): controller="'.$this->controller
581        //          .'"  action="'.$this->action.'"');
582
583        # Include main application controller file
584        if(file_exists($this->application_controller_file)) {
585            include_once($this->application_controller_file);
586        }
587
588        # If controller is loaded then start processing           
589        if($this->loaded) {
590           
591            include_once($this->controller_file);           
592            if(class_exists($this->controller_class, false)) {               
593                $class = $this->controller_class;
594                $this->controller_object = new $class();               
595            }
596           
597            if(is_object($this->controller_object)) {
598                $this->controller_object->controller = $this->controller;
599                $this->controller_object->action = $this->action;
600                $this->controller_object->controller_path = "$this->added_path/$this->controller";
601                $this->controller_object->views_path = $this->views_path;
602                $this->controller_object->layouts_path = $this->layouts_path;
603                Trax::$current_controller_path = "$this->added_path/$this->controller";
604                Trax::$current_controller_name = $this->controller;
605                Trax::$current_action_name = $this->action;
606                Trax::$current_controller_object =& $this->controller_object;
607                # Which layout should we use?
608                $this->controller_object->determine_layout();
609                # Check if there is any defined scaffolding to load
610                if(isset($this->controller_object->scaffold)) {
611                    $scaffold = $this->controller_object->scaffold;
612                    if(file_exists(TRAX_LIB_ROOT."/scaffold_controller.php")) {
613                        include_once(TRAX_LIB_ROOT."/scaffold_controller.php");
614                        $this->controller_object = new ScaffoldController($scaffold);
615                        Trax::$current_controller_object =& $this->controller_object;
616                        $render_options['scaffold'] = true;
617                        if(!file_exists($this->controller_object->layout_file)) {
618                            # the generic scaffold layout
619                            $this->controller_object->layout_file = TRAX_LIB_ROOT . "/templates/scaffolds/layout.phtml";
620                        }
621                    }
622                }
623
624                # Include main application helper file
625                if(file_exists($this->application_helper_file)) {
626                    include_once($this->application_helper_file);
627                }
628   
629                # Include helper file for this controller
630                if(file_exists($this->helper_file)) {
631                    include_once($this->helper_file);
632                }                               
633
634                # Include any extra helper files defined in this controller
635                if(count($this->controller_object->helpers) > 0) {
636                    foreach($this->controller_object->helpers as $helper) {
637                        if(strstr($helper, "/")) {
638                            $file = substr(strrchr($helper, "/"), 1);
639                            $path = substr($helper, 0, strripos($helper, "/"));
640                            $helper_path_with_file = $this->helpers_base_path."/".$path."/".$file."_helper.php";
641                        } else {
642                            $helper_path_with_file = $this->helpers_base_path."/".$helper."_helper.php";
643                        }
644
645                        if(file_exists($helper_path_with_file)) {
646                            # Include the helper file
647                            include($helper_path_with_file);
648                        }
649                    }
650                }
651
652                # Suppress output
653                ob_start();
654                #error_log('started capturing HTML');
655               
656                # Call the controller method based on the URL
657                if($this->controller_object->execute_before_filters()) {
658                    $controller_layout = null;
659                    if(isset($this->controller_object->layout)) {
660                        $controller_layout = $this->controller_object->layout;       
661                    }
662
663                    #Get PUBLIC methods from controller object
664                    $all_methods = get_class_methods($this->controller_object); 
665
666                    # Get Inherited methods from active_controller
667                    $inherited_methods = array_merge(
668                        get_class_methods(__CLASS__),
669                        $this->controller_object->before_filters,
670                        $this->controller_object->after_filters
671                    );
672
673                    # Get non-inherited methods
674                    $action_methods = array_diff($all_methods, $inherited_methods);
675                    #error_log("available methods:".print_r($action_methods, true));
676
677                    if(in_array($this->action, $action_methods)) {
678                        #error_log('method '.$this->action.' exists, calling it');
679                        $action = $this->controller_object->called_action = $this->action;
680                        #error_log('calling action routine '
681                        #          . get_class($this->controller_object)
682                        #          .'::'.$action.'()');
683                        $this->controller_object->$action();
684                    } elseif(file_exists($this->views_path . "/" . $this->action . "." . Trax::$views_extension)) {
685                        #error_log('views file "'.$this->action.'"');
686                        $action = $this->controller_object->called_action = $this->action;
687                    } elseif(method_exists($this->controller_object, "index")) {
688                        #error_log('calling action routine '
689                        #          . get_class($this->controller_object)
690                        #          .'::index()');
691                        $action = $this->controller_object->called_action = "index";
692                        $this->controller_object->index();
693                    } else {
694                        //error_log('no action');   
695                        $methods_size = count($action_methods);       
696                        if($methods_size > 1) {
697                            $last_method = ($methods_size > 2 ? "," : '')." and ".array_pop($action_methods);
698                        }
699                        $this->raise("No action responded to ".$this->action.". Actions:".implode(", ",$action_methods).$last_method, "Unknown action", "404");
700                    }
701                   
702                    if(isset($this->controller_object->layout)) {
703                        if($controller_layout != $this->controller_object->layout) {
704                            # layout was set in the action need to redetermine the layout file to use.
705                            $this->controller_object->determine_layout();
706                        }       
707                    }
708                   
709                    $this->controller_object->execute_after_filters();
710                   
711                    $this->controller_object->action_called = true;
712                   
713                    # Find out if there was a redirect to some other page
714                    if(isset($this->controller_object->redirect_to)
715                        && $this->controller_object->redirect_to != '') {
716                        $this->redirect_to($this->controller_object->redirect_to);
717                        # execution will end here redirecting to new page
718                    } 
719                   
720                    # If render_text was defined as a string render it                   
721                    if(isset($this->controller_object->render_text)
722                       && $this->controller_object->render_text != "") {
723                        $this->render_text($this->controller_object->render_text);
724                        # execution will end here rendering only the text no layout
725                    } 
726                                   
727                    # If defined string render_action use that instead
728                    if(isset($this->controller_object->render_action)
729                       && $this->controller_object->render_action != '') {
730                        $action = $this->controller_object->render_action;
731                    } 
732                   
733                    # Render the action / view                     
734                    if(!$this->controller_object->render_action($action,
735                          isset($render_options) ? $render_options : null )) {
736                        $this->raise("No view file found $action ($this->view_file).", "Unknown view", "404"); 
737                    }
738                    # Grab all the html from the view to put into the layout
739                    $content_for_layout = ob_get_contents();
740                    ob_end_clean();
741                    //error_log("captured ".strlen($content_for_layout)." bytes\n");
742                    if(isset($this->controller_object->render_layout)
743                       && ($this->controller_object->render_layout !== false)
744                       && $this->controller_object->layout_file) {
745                        $locals['content_for_layout'] = $content_for_layout;
746                        # render the layout
747                        #error_log("rendering layout: ".$this->controller_object->layout_file);
748                        if(!$this->controller_object->render_file($this->controller_object->layout_file, false, $locals)) {
749                            # No layout template so just echo out whatever is in $content_for_layout
750                            //echo "HERE";
751                            echo $content_for_layout;       
752                        }
753                    } else {
754                        # Can't find any layout so throw an exception
755                        # $this->raise("No layout file found.", "Unknown layout", "404");
756                        # No layout template so just echo out whatever is in $content_for_layout
757                        //error_log("no layout found: ".$this->controller_object->layout_file);
758                        echo $content_for_layout;
759                    }
760                }       
761            } else {
762                $this->raise("Failed to instantiate controller object \"".$this->controller."\".", "ActionController Error", "500");
763            }
764        } else {
765            $this->raise("No controller found.", "Unknown controller", "404");
766        }
767
768        // error_log('keep flash='.var_export($this->keep_flash,true));
769        if(!$this->keep_flash) {
770            # Nuke the flash
771            unset($_SESSION['flash']);
772            Session::unset_var('flash');
773        }
774
775        return true;
776    } // function process_route()
777
778    /**
779     *  Extend the search path for components
780     *
781     *  On entry, $url_path is set according to the browser's URL and
782     *  $controllers_path has been set according to the configuration
783     *  in {@link environment.php config/environment.php} .  Examine
784     *  the $controllers_path directory for files or directories that
785     *  match any component of the URL.  If one is found, add that
786     *  component to all paths.  Replace the contents of $url_path
787     *  with the list of URL components that did NOT match any files
788     *  or directories.
789     *  @uses $added_path
790     *  @uses $controllers_path
791     *  @uses $helpers_path
792     *  @uses $layouts_path
793     *  @uses $views_path
794     *  @uses $url_path
795     */
796    function set_paths() {
797        if(is_array($this->url_path)) {                     
798            $path_size = count($this->url_path) - 1;
799            $test_path = $this->controllers_path; 
800            $url_path = $this->url_path;         
801            foreach($url_path as $position => $path) {         
802                $test_path .= "/$path"; 
803                $test_file = $test_path."_controller.php";                 
804                if(is_file($test_file)) {     
805                    $next = isset($url_path[$position+1]) ? 
806                        $test_path ."/".$url_path[$position+1] :
807                        null;     
808                    if(!is_null($next)) {
809                        if(is_file($next."_controller.php") || is_dir($next)) {
810                            $extra_path[] = $path;   
811                            array_shift($this->url_path);                           
812                        }
813                    } else {
814                        #error_log("found controller path:$path");                   
815                        break;                       
816                    }             
817                } elseif(is_dir($test_path)) {     
818                    $extra_path[] = $path;   
819                    array_shift($this->url_path);
820                }
821            }
822            if(isset($extra_path) && is_array($extra_path)) { 
823                #error_log("extra_path:".print_r($extra_path, true));
824                $this->extra_path = $extra_path;
825                $extra_path = implode("/", $extra_path);
826                $this->added_path = $extra_path;
827                $this->controllers_path .= "/$extra_path";
828                $this->helpers_path .= "/$extra_path";
829                $this->views_path .= "/$extra_path";
830                $this->layouts_path .= "/$extra_path";
831            }
832        }
833    }
834
835    /**
836     *  Execute the before filters
837     *  @uses $before_filters
838     */
839    function execute_before_filters() {
840   
841        #if(isset($this->before_filter)) {
842            #$this->add_before_filter($this->before_filter);
843        #}
844        #error_log("before_filters:".print_r($this->before_filters, true));
845        #error_log("before_filter_options:".print_r($this->before_filter_options, true));       
846        $return = true;
847        if(count($this->before_filters) > 0) { 
848            $action = $this->action ? $this->action : "index";
849            foreach($this->before_filters as $filter_function) {
850                if(array_key_exists($filter_function, $this->before_filter_options)) {
851                    if(is_array($options = $this->before_filter_options[$filter_function])) {
852                        if(array_key_exists('except', $options)) {
853                            if(preg_match("/\b$action\b/", $options['except'])) {
854                                #error_log("before filter except match: action:{$action} == ".$options['except']);
855                                continue;     
856                            }                       
857                        }
858                        if(array_key_exists('only', $options)) {
859                            if(!preg_match("/\b$action\b/", $options['only'])) {
860                                #error_log("before filter only non match: action:{$action} == ".$options['only']);
861                                continue;     
862                            }                       
863                        }                       
864                    }
865                }
866                if(method_exists($this, $filter_function)) {
867                    if(false === $this->$filter_function()) {
868                        //error_log("execute_before_filters(): returning false");
869                        $return = false;   
870                    }
871                }
872            }
873        }
874        return $return;
875    }
876
877    /**
878     *  Append a before filter to the filter chain
879     *
880     *  @param mixed $filter_function_name  String with the name of
881     *  one filter function, or array of strings with the names of
882     *  several filter functions.
883     *  @uses $before_filters
884     */
885    function add_before_filter($filter_function_name, $options = array(), $prepend = false) {
886        //error_log("adding before filter: $filter_function_name");
887        if(is_string($filter_function_name) && !empty($filter_function_name)) {
888            if(!in_array($filter_function_name, $this->before_filters)) {
889                if($prepend) {
890                    array_unshift($this->before_filters, $filter_function_name);
891                } else {
892                    array_push($this->before_filters, $filter_function_name);
893                }
894                if(count($options)) {
895                    if(count($this->before_filter_options[$filter_function_name])) {
896                        $this->before_filter_options[$filter_function_name] = array_merge($this->before_filter_options[$filter_function_name], $options);
897                    } else {
898                        $this->before_filter_options[$filter_function_name] = $options;
899                    }                                       
900                }
901            }                       
902        } elseif(is_array($filter_function_name)) {
903            foreach($filter_function_name as $filter_name => $options) {
904                if(!in_array($filter_name, $this->before_filters)) {
905                    if($prepend) {
906                        array_unshift($this->before_filters, $filter_name);
907                    } else {
908                        array_push($this->before_filters, $filter_name);
909                    }   
910                    if(count($options)) {
911                        if(count($this->before_filter_options[$filter_name])) {
912                            $this->before_filter_options[$filter_name] = array_merge($this->before_filter_options[$filter_name], $options);
913                        } else {
914                            $this->before_filter_options[$filter_name] = $options;
915                        }                                       
916                    }
917                }               
918            }
919        }
920    }
921
922    function prepend_before_filter($filter_function_name, $options = array()) {
923        $this->add_before_filter($filter_function_name, $options, true);
924    }
925
926    /**
927     *  Execute the after filters
928     *  @uses $after_filters
929     */
930    function execute_after_filters() {
931   
932        #if(isset($this->after_filter)) {
933            #$this->add_after_filter($this->after_filter);
934        #}
935        #error_log("after_filters:".print_r($this->after_filters, true));
936        #error_log("after_filter_options:".print_r($this->after_filter_options, true));     
937        $return = true;
938        if(count($this->after_filters) > 0) { 
939            $action = $this->action ? $this->action : "index";
940            foreach($this->after_filters as $filter_function) {
941                if(array_key_exists($filter_function, $this->after_filter_options)) {
942                    if(is_array($options = $this->after_filter_options[$filter_function])) {
943                        if(array_key_exists('except', $options)) {
944                            if(preg_match("/\b$action\b/", $options['except'])) {
945                                #error_log("after filter except match: action:{$action} == ".$options['except']);
946                                continue;     
947                            }                       
948                        }
949                        if(array_key_exists('only', $options)) {
950                            if(!preg_match("/\b$action\b/", $options['only'])) {
951                                #error_log("after filter only non match: action:{$action} == ".$options['only']);
952                                continue;     
953                            }                       
954                        }                       
955                    }
956                }
957                if(method_exists($this, $filter_function)) {
958                    if(false === $this->$filter_function()) {
959                        //error_log("execute_after_filters(): returning false");
960                        $return = false;   
961                    }
962                }
963            }
964        }
965        return $return;
966    }
967
968    /**
969     *  Append an after filter to the filter chain
970     *
971     *  @param mixed $filter_function_name  String with the name of
972     *  one filter function, or array of strings with the names of
973     *  several filter functions.
974     *  @uses $after_filters
975     */
976    function add_after_filter($filter_function_name, $options = array(), $prepend = false) {
977        //error_log("adding after filter: $filter_function_name");
978        if(is_string($filter_function_name) && !empty($filter_function_name)) {
979            if(!in_array($filter_function_name, $this->after_filters)) {
980                if($prepend) {
981                    array_unshift($this->after_filters, $filter_function_name);
982                } else {
983                    array_push($this->after_filters, $filter_function_name);
984                }
985                if(count($options)) {
986                    if(count($this->after_filter_options[$filter_function_name])) {
987                        $this->after_filter_options[$filter_function_name] = array_merge($this->after_filter_options[$filter_function_name], $options);
988                    } else {
989                        $this->after_filter_options[$filter_function_name] = $options;
990                    }                                       
991                }
992            }                       
993        } elseif(is_array($filter_function_name)) {
994            foreach($filter_function_name as $filter_name => $options) {
995                if(!in_array($filter_name, $this->after_filters)) {
996                    if($prepend) {
997                        array_unshift($this->after_filters, $filter_name);
998                    } else {
999                        array_push($this->after_filters, $filter_name);
1000                    }   
1001                    if(count($options)) {
1002                        if(count($this->after_filter_options[$filter_name])) {
1003                            $this->after_filter_options[$filter_name] = array_merge($this->after_filter_options[$filter_name], $options);
1004                        } else {
1005                            $this->after_filter_options[$filter_name] = $options;
1006                        }                                       
1007                    }
1008                }               
1009            }
1010        }
1011    }
1012
1013    function prepend_after_filter($filter_function_name, $options = array()) {
1014        $this->add_after_filter($filter_function_name, $options, true);
1015    }
1016
1017    /**
1018     *  Add a helper to the list of helpers used by a controller
1019     *  object
1020     *
1021     *  @param $helper_name string Name of a helper to add to the list
1022     *  @uses  $helpers
1023     *  @uses  $controller_object
1024     */
1025    function add_helper($helper_name) {
1026        if(!in_array($helper_name, $this->helpers)) {
1027            $this->helpers[] = $helper_name;
1028        }
1029    }
1030
1031    /**
1032     *
1033     * Renders the content that will be returned to the browser as the response body.
1034     *
1035     */
1036    function render($options = array(), $locals = array(), $return_as_string = false) {
1037       
1038        if($this->render_performed && !$this->action_called) {
1039            return true;   
1040        }
1041       
1042        if($return_as_string) {
1043            # start to buffer output
1044            ob_start();     
1045        }
1046     
1047        if(is_string($options)) {         
1048            $this->render_file($options, true, $locals);       
1049        } elseif(is_array($options)) {
1050            $options['locals'] = $options['locals'] ? $options['locals'] : array();
1051            $options['use_full_path'] = !$options['use_full_path'] ? true : $options['use_full_path'];
1052                 
1053            if($options['text']) {
1054                $this->render_text($options['text']);       
1055            } else {
1056                if($options['action']) {
1057                    $this->render_action($options['action'], $options);       
1058                } elseif($options['file']) {
1059                    $this->render_file($options['file'], $options['use_full_path'], $options['locals']);   
1060                } elseif($options['partial']) {
1061                    $this->render_partial($options['partial'], $options);       
1062                } elseif($options['nothing']) {
1063                    # Safari doesn't pass the headers of the return if the response is zero length
1064                    $this->render_text(" "); 
1065                }   
1066            }
1067        } 
1068       
1069        $this->render_performed = true;
1070
1071        if($return_as_string) {
1072            $result = ob_get_contents();
1073            ob_end_clean(); 
1074            $this->render_performed = false;
1075            return $result;
1076        }         
1077    }
1078   
1079    /**
1080     *
1081     * Rendering of text is usually used for tests or for rendering prepared content.
1082     * By default, text rendering is not done within the active layout.
1083     *
1084     *   # Renders the clear text "hello world"
1085     *   render(array("text" => "hello world!"))
1086     *
1087     *   # Renders the clear text "Explosion!"
1088     *   render(array("text" => "Explosion!"))
1089     *
1090     *   # Renders the clear text "Hi there!" within the current active layout (if one exists)
1091     *   render(array("text" => "Explosion!", "layout" => true))
1092     *
1093     *   # Renders the clear text "Hi there!" within the layout
1094     *   # placed in "app/views/layouts/special.phtml"
1095     *   render(array("text" => "Explosion!", "layout" => "special"))
1096     *
1097     */
1098    function render_text($text, $options = array()) {       
1099        if($options['layout']) {
1100            $locals['content_for_layout'] = $text;         
1101            $layout = $this->determine_layout();
1102            $this->render_file($layout, false, $locals); 
1103        } else {
1104            echo $text;   
1105        }
1106        exit;     
1107    }
1108
1109    /**
1110     *
1111     * Action rendering is the most common form and the type used automatically by
1112     * Action Controller when nothing else is specified. By default, actions are
1113     * rendered within the current layout (if one exists).
1114     *
1115     *   # Renders the template for the action "goal" within the current controller
1116     *   render(array("action" => "goal"))
1117     *
1118     *   # Renders the template for the action "short_goal" within the current controller,
1119     *   # but without the current active layout
1120     *   render(array("action" => "short_goal", "layout" => false))
1121     *
1122     *   # Renders the template for the action "long_goal" within the current controller,
1123     *   # but with a custom layout
1124     *   render(array("action" => "long_goal", "layout" => "spectacular"))
1125     *
1126     */   
1127    function render_action($action, $options = array()) {
1128        if($this->render_performed) {
1129            return true;   
1130        }
1131        if($options['layout']) {
1132            $this->layout = $options['layout'];   
1133        } 
1134        if($options['scaffold']) {
1135            $this->view_file = TRAX_LIB_ROOT."/templates/scaffolds/".$action.".phtml";   
1136        } else {   
1137            $this->view_file = $this->views_path . "/" . $action . "." . Trax::$views_extension;
1138        }
1139        //error_log(get_class($this)." - render_action() view_file: $this->view_file");
1140        return $this->render_file($this->view_file);
1141    }
1142   
1143    /**
1144     *
1145     * Renders according to the same rules as render, but returns the result in a string
1146     * instead of sending it as the response body to the browser.
1147     *   
1148     */
1149    function render_to_string($options = array(), $locals = array()) {
1150        return $this->render($options, $locals, true);   
1151    }
1152
1153    /**
1154     *
1155     * File rendering works just like action rendering except that it takes a filesystem path.
1156     * By default, the path is assumed to be absolute, and the current layout is not applied.
1157     *
1158     *   # Renders the template located at the absolute filesystem path
1159     *   render(array("file" => "/path/to/some/template.phtml"))
1160     *   render(array("file" => "c:/path/to/some/template.phtml"))
1161     *
1162     *   # Renders a template within the current layout
1163     *   render(array("file" => "/path/to/some/template.rhtml", "layout" => true))
1164     *   render(array("file" => "c:/path/to/some/template.rhtml", "layout" => true))
1165     *
1166     *   # Renders a template relative to app/views
1167     *   render(array("file" => "some/template", "use_full_path" => true))
1168     */
1169    function render_file($path, $use_full_path = false, $locals = array()) {
1170        if($this->render_performed && !$this->action_called) {
1171            return true;   
1172        }       
1173       
1174        # Renders a template relative to app/views
1175        if($use_full_path) {
1176            $path = $this->views_path."/".$path.".".Trax::$views_extension;
1177        } 
1178
1179        //error_log("render_file() path:$path");
1180        if(file_exists($path)) {
1181
1182            # Pull all the class vars out and turn them from $this->var to $var
1183            if(is_object($this)) {
1184                $controller_locals = get_object_vars($this);
1185            }
1186            if(is_array($controller_locals)) {
1187                $locals = array_merge($controller_locals, $locals);   
1188            }                   
1189            if(count($locals)) {
1190                foreach($locals as $tmp_key => $tmp_value) {
1191                    ${$tmp_key} = $tmp_value;               
1192                }   
1193                unset($tmp_key);
1194                unset($tmp_value);
1195            }     
1196            include($path);
1197            $this->render_performed = true; 
1198            return true;     
1199        }     
1200        return false;     
1201    }
1202
1203    /**
1204     *  Rendering partials
1205     *
1206     *  <p>Partial rendering is most commonly used together with Ajax
1207     *  calls that only update one or a few elements on a page without
1208     *  reloading. Rendering of partials from the controller makes it
1209     *  possible to use the same partial template in both the
1210     *  full-page rendering (by calling it from within the template)
1211     *  and when sub-page updates happen (from the controller action
1212     *  responding to Ajax calls). By default, the current layout is
1213     *  not used.</p>
1214     *
1215     *  <ul>
1216     *    <li><samp>render_partial("win");</samp><br>
1217     *      Renders the partial
1218     *      located at app/views/controller/_win.phtml</li>
1219     *
1220     *    <li><samp>render_partial("win",
1221     *       array("locals" => array("name" => "david")));</samp><br>
1222     *      Renders the same partial but also makes a local variable
1223     *      available to it</li>
1224     *     
1225     *    <li><samp>render_partial("win",
1226     *      array("collection" => array(...)));</samp><br>
1227     *      Renders a collection of the same partial by making each
1228     *      element of the collection available through the local variable
1229     *      "win" as it builds the complete response </li>
1230     *
1231     *    <li><samp>render_partial("win", array("collection" => $wins,
1232     *      "spacer_template" => "win_divider"));</samp><br>
1233     *      Renders the same collection of partials, but also renders
1234     *      the win_divider partial in between each win partial.</li>
1235     *  </ul>
1236     *  @param string $path Path to file containing partial view
1237     *  @param string[] $options Options array
1238     */
1239    function render_partial($path, $options = array()) {
1240        if(strstr($path, "/")) {
1241            $file = substr(strrchr($path, "/"), 1);
1242            $path = substr($path, 0, strripos($path, "/"));
1243            $file_with_path = Trax::$views_path."/".$path."/_".$file.".".Trax::$views_extension;
1244        } else {
1245            $file = $path;
1246            $file_with_path = $this->views_path."/_".$file.".".Trax::$views_extension;
1247        }
1248       
1249        if(file_exists($file_with_path)) {
1250           
1251            if(array_key_exists("spacer_template", $options)) {
1252                $spacer_path = $options['spacer_template'];
1253                if(strstr($spacer_path, "/")) {
1254                    $spacer_file = substr(strrchr($spacer_path, "/"), 1);
1255                    $spacer_path = substr($spacer_path, 0, strripos($spacer_path, "/"));
1256                    $spacer_file_with_file = Trax::$views_path."/".$spacer_path."/_".$spacer_file.".".Trax::$views_extension;
1257                } else {
1258                    $spacer_file = $spacer_path;
1259                    $spacer_file_with_file = $this->views_path."/_".$spacer_file.".".Trax::$views_extension;
1260                } 
1261                if(file_exists($spacer_file_with_file)) {
1262                    $add_spacer = true;   
1263                }
1264            }         
1265
1266            $locals = array_key_exists("locals", $options) ? $options['locals'] : array();
1267            if(array_key_exists("collection", $options) && is_array($options['collection'])) {
1268                foreach($options['collection'] as $tmp_value) {
1269                    ${$file."_counter"}++;
1270                    $locals[$file] = $tmp_value;
1271                    $locals[$file."_counter"] = ${$file."_counter"};
1272                    unset($tmp_value); 
1273                    $this->render_performed = false;
1274                    $this->render_file($file_with_path, false, $locals);   
1275                    if($add_spacer && (${$file."_counter"} < count($options['collection']))) { 
1276                        $this->render_performed = false;
1277                        $this->render_file($spacer_file_with_file, false, $locals);     
1278                    }         
1279                } 
1280                $this->render_performed = true;   
1281            } else {             
1282                $this->render_file($file_with_path, false, $locals);       
1283            }         
1284        }
1285    }
1286
1287    /**
1288     *  Select a layout file based on the controller object
1289     *
1290     *  @uses $controller_object
1291     *  @uses $layouts_base_path
1292     *  @uses $layouts_path
1293     *  @return mixed Layout file or null if none
1294     *  @todo <b>FIXME:</b> Should this method be private?
1295     */
1296    function determine_layout($full_path = true) {
1297
1298        //  If the controller defines $layout and sets it
1299        //  to NULL, that indicates it doesn't want a layout
1300        if(isset($this->layout) && is_null($this->layout)) {
1301            //error_log('controller->layout absent');
1302            return null;
1303        }
1304        # $layout will be the layout defined in the current controller
1305        # or try to use the controller name for the layout
1306        $layout = (isset($this->layout)
1307                   && $this->layout != '')
1308            ? $this->layout : $this->controller;
1309   
1310        # Check if a method has been defined to determine the layout at runtime
1311        if(method_exists($this, $layout)) {
1312            $layout = $this->$layout();
1313        }
1314
1315        # Default settings
1316        $layouts_base_path = Trax::$layouts_path;
1317        $default_layout_file = $layouts_base_path . "/application." . Trax::$views_extension;
1318       
1319        if(!$full_path && $layout) {
1320            return $layout;       
1321        } elseif($layout) {
1322            # Is this layout for from a different controller
1323            if(strstr($layout, "/")) {
1324                $file = substr(strrchr($layout, "/"), 1);
1325                $path = substr($layout, 0, strripos($layout, "/"));
1326                $layout = $layouts_base_path."/".$path."/".$file.".".Trax::$views_extension;
1327            } elseif(file_exists($this->layouts_path."/".$layout.".".Trax::$views_extension)) {
1328                # Is there a layout for the current controller
1329                $layout = $this->layouts_path."/".$layout.".".Trax::$views_extension;
1330            } else {
1331                $layout = $layouts_base_path."/".$layout.".".Trax::$views_extension;
1332            }
1333            if(file_exists($layout)) {
1334                $layout_file = $layout;
1335            }
1336        }
1337       
1338        # No defined layout found so just use the default layout
1339        # app/views/layouts/application.phtml
1340        if(!isset($layout_file)) {
1341            $layout_file = $default_layout_file;
1342        }
1343        $this->layout_file = $layout_file;
1344        return $layout_file;
1345    }
1346
1347    /**
1348     *  Redirect the browser to a specified target
1349     *
1350     *  Redirect the browser to the target specified in $options. This
1351     *  parameter can take one of three forms:
1352     *  <ul>
1353     *    <li>Array: The URL will be generated by calling
1354     *      {@link url_for()} with the options.</li>
1355     *    <li>String starting with a protocol:// (like http://): Is
1356     *      passed straight through as the target for redirection.</li>
1357     *    <li>String not containing a protocol: The current protocol
1358     *      and host is prepended to the string.</li>
1359     *    <li>back: Back to the page that issued the request. Useful
1360     *      for forms that are triggered from multiple
1361     *      places. Short-hand for redirect_to(request.env["HTTP_REFERER"])
1362     *   </ul>
1363     *
1364     *  Examples:
1365     *  <ul>
1366     *    <li>redirect_to(array(":action" => "show", ":id" => 5))</li>
1367     *    <li>redirect_to("http://www.rubyonrails.org")</li>
1368     *    <li>redirect_to("/images/screenshot.jpg")</li>
1369     *    <li>redirect_to("back")</li>
1370     *  </ul>
1371     *
1372     *  @param mixed $options array or string url 
1373     *  @todo <b>FIXME:</b> Make header configurable
1374     */   
1375    function redirect_to($options = null) {
1376        if($options == "back") {
1377            $url = $_SERVER["HTTP_REFERER"];
1378        } else {
1379            $url = url_for($options);     
1380        }
1381       
1382        if(headers_sent()) {
1383            echo "<html><head><META HTTP-EQUIV=\"REFRESH\" CONTENT=\"0; URL=".$url."\"></head></html>";
1384        } else {
1385            header("Location: ".$url);
1386        }       
1387 
1388        exit;           
1389    }
1390
1391    /**
1392     *  Sets content passed in or echoed after calling this function and sets it
1393     *  to a variable named $content_for_"$name" to be used in the layout.
1394     *  Example:
1395     *  View:
1396     *  <? $this->content_for("navigation") ?>
1397     *      <li><?= link_to('Login', array(":action" => 'login')) ?></li>
1398     *  <? $this->end_content_for() ?>
1399     *  Layout:
1400     *  <?= $content_for_navigation ?>
1401     *
1402     *  @param string $name variable name to be set for use in layout
1403     *  @param string $content (optional) content for the variable to be set
1404     */
1405    function content_for($name, $content = null) {
1406        array_push($this->content_for_open_blocks, $name);
1407        ob_start();
1408        if($content) {
1409            echo $content;
1410            $this->end_content_for();
1411        }
1412    }
1413
1414    /**
1415     *  Ends an open block call by content_for() and sets the content of the buffer
1416     *  to the variable $content_for_"name"
1417     */ 
1418    function end_content_for() {   
1419        if(count($this->content_for_open_blocks)) {     
1420            if($name = array_pop($this->content_for_open_blocks)) {
1421                $content = ob_get_contents();
1422                ob_end_clean();
1423                $this->{"content_for_".$name} = $content;
1424            } else {
1425                ob_end_clean();
1426            }
1427        } 
1428    }
1429
1430    /**
1431     *  Raise an ActionControllerError exception
1432     *
1433     *  @param string $error_message Error message
1434     *  @param string $error_heading Error heading
1435     *  @param string $error_code    Error code
1436     *  @throws ActionControllerError
1437     */
1438    function raise($error_message, $error_heading, $error_code = "404") { 
1439        throw new ActionControllerError("Error Message: ".$error_message, $error_heading, $error_code);
1440    }
1441
1442    /**
1443     *  Generate an HTML page describing an error
1444     */
1445    function process_with_exception(&$exception) {
1446        $error_code = $exception->error_code;
1447        $error_heading = $exception->error_heading;
1448        $error_message = $exception->error_message;
1449        $trace = $exception->getTraceAsString();
1450        header("HTTP/1.0 {$error_code} {$error_heading}");
1451        # check for user's layout for errors
1452        if(TRAX_ENV == "development" || Trax::$show_trax_errors) {
1453            if(file_exists(Trax::$layouts_path."/trax_error.".Trax::$views_extension)) {
1454                include(Trax::$layouts_path."/trax_error.".Trax::$views_extension);
1455            } elseif(file_exists(TRAX_LIB_ROOT."/templates/error.phtml")) {
1456                # use default layout for errors
1457                include(TRAX_LIB_ROOT."/templates/error.phtml");
1458            } else {
1459                echo "<font face=\"verdana, arial, helvetica, sans-serif\">\n";
1460                echo "<h1>$error_heading</h1>\n";
1461                echo "<p>$error_message</p>\n";
1462                if($trace) {
1463                    echo "<pre style=\"background-color: #eee;padding:10px;font-size: 11px;\">";
1464                    echo "<code>$trace</code></pre>\n";
1465                }
1466                echo "</font>\n";               
1467            }
1468        } else {
1469            if($error_code == "404") {
1470                echo "<h2>404 Error - File not found.</h2>";
1471            } else {
1472                echo "<font face=\"verdana, arial, helvetica, sans-serif\">\n";
1473                echo "<h2>Application Error</h2>Trax application failed to start properly";
1474                echo "</font>\n";               
1475            }           
1476        } 
1477     
1478    }
1479
1480}
1481
1482// -- set Emacs parameters --
1483// Local variables:
1484// tab-width: 4
1485// c-basic-offset: 4
1486// c-hanging-comment-ender-p: nil
1487// indent-tabs-mode: nil
1488// End:
1489?>
Note: See TracBrowser for help on using the browser.