Changeset 1448

Show
Ignore:
Timestamp:
01/01/07 19:42:27 (23 months ago)
Author:
david
Message:

work in progress: new execution flow, action stack is gone, decoration doesn't require special abilities of the renderer anymore, but still needs further abstraction. decorators in decorators (for slots) should work now, and slots are available in the main content template. also, caching for execution filter is in place, albeit not enabled/complete yet. refs #373, #377, #287 and #290

Location:
branches/david-execution_flow
Files:
1 added
3 removed
21 modified

Legend:

Unmodified
Added
Removed
  • branches/david-execution_flow/docs/docbook/manual.xml

    r1421 r1448  
    16351635 
    16361636  <handlers> 
    1637    <handler pattern="%core.module_dir%/*/config/rendering_filters.xml" validate="%core.agavi_dir%/config/xsd/filters.xsd" class="AgaviFilterConfigHandler" /> 
     1637   <handler pattern="%core.module_dir%/*/config/action_filters.xml" validate="%core.agavi_dir%/config/xsd/filters.xsd" class="AgaviFilterConfigHandler" /> 
    16381638   <handler pattern="%core.module_dir%/*/config/module.xml" validate="%core.agavi_dir%/config/xsd/module.xsd" class="AgaviModuleConfigHandler" /> 
    16391639   <handler pattern="%core.module_dir%/*/validate/*.xml" class="AgaviValidatorConfigHandler" /> 
     
    19021902      <title>FilterConfigHandler Tags (*_filters.xml)</title> 
    19031903 
    1904       <para>You may use <filename>action_filters.xml</filename>, 
    1905       <filename>global_filters.xml</filename> and 
    1906       <filename>rendering_filters.xml</filename> to configure Action, global 
    1907       or rendering filters. Action and rendering filters may also be specified 
    1908       on a per-module basis by putting them into the 
     1904      <para>You may use <filename>action_filters.xml</filename> and 
     1905      <filename>global_filters.xml</filename> to configure filters that wrap 
     1906      either the global execution flow or individual actions. Action filters 
     1907      may also be specified on a per-module basis by putting them into the 
    19091908      <filename>app/modules/ModuleName/config/</filename> folder.</para> 
    19101909 
  • branches/david-execution_flow/samples/app/lib/filter/AgaviSampleAppCookieLoginFilter.class.php

    r908 r1448  
    2727   * @since      0.11.0 
    2828   */ 
    29   public function execute(AgaviFilterChain $filterChain, AgaviResponse $response) 
     29  public function execute(AgaviFilterChain $filterChain, AgaviExecutionContainer $container) 
    3030  { 
    3131    $req = $this->getContext()->getRequest(); 
     
    4343    } 
    4444     
    45     $filterChain->execute($filterChain, $response); 
     45    $filterChain->execute($container); 
    4646  } 
    4747} 
  • branches/david-execution_flow/src/action/AgaviAction.class.php

    r1408 r1448  
    2929 * @version    $Id$ 
    3030 */ 
    31 abstract class AgaviAction extends AgaviAttributeHolder 
     31abstract class AgaviAction 
    3232{ 
    3333  /** 
    3434   * @var        AgaviContext An AgaviContext instance. 
    3535   */ 
     36  private $container = null; 
     37 
     38  /** 
     39   * @var        AgaviContext An AgaviContext instance. 
     40   */ 
    3641  private $context = null; 
    3742 
     
    4752  { 
    4853    return $this->context; 
     54  } 
     55 
     56  public final function getContainer() 
     57  { 
     58    return $this->container; 
    4959  } 
    5060 
     
    91101   * @since      0.9.0 
    92102   */ 
    93   public function initialize(AgaviContext $context) 
    94   { 
    95     $this->context = $context; 
     103  public function initialize(AgaviExecutionContainer $container) 
     104  { 
     105    $this->container = $container; 
     106     
     107    $this->context = $container->getContext(); 
    96108  } 
    97109 
     
    148160    return 'Input'; 
    149161  } 
     162 
     163  /** 
     164   * @see        AgaviAttributeHolder::setAttributesByRef() 
     165   * 
     166   * @author     David Zuelke <dz@bitxtender.com> 
     167   * @since      0.9.0 
     168   */ 
     169  public function clearAttributes() 
     170  { 
     171    $this->container->clearAttributes(); 
     172  } 
     173 
     174  /** 
     175   * @see        AgaviAttributeHolder::setAttributesByRef() 
     176   * 
     177   * @author     David Zuelke <dz@bitxtender.com> 
     178   * @since      0.9.0 
     179   */ 
     180  public function & getAttribute($name, $default = null) 
     181  { 
     182    return $this->container->getAttribute($name, null, $default); 
     183  } 
     184 
     185  /** 
     186   * @see        AgaviAttributeHolder::setAttributesByRef() 
     187   * 
     188   * @author     David Zuelke <dz@bitxtender.com> 
     189   * @since      0.9.0 
     190   */ 
     191  public function getAttributeNames() 
     192  { 
     193    return $this->container->getAttributeNames(); 
     194  } 
     195 
     196  /** 
     197   * @see        AgaviAttributeHolder::setAttributesByRef() 
     198   * 
     199   * @author     David Zuelke <dz@bitxtender.com> 
     200   * @since      0.11.0 
     201   */ 
     202  public function & getAttributes() 
     203  { 
     204    return $this->container->getAttributes(); 
     205  } 
     206 
     207  /** 
     208   * @see        AgaviAttributeHolder::setAttributesByRef() 
     209   * 
     210   * @author     David Zuelke <dz@bitxtender.com> 
     211   * @since      0.9.0 
     212   */ 
     213  public function hasAttribute($name) 
     214  { 
     215    return $this->container->hasAttribute($name); 
     216  } 
     217 
     218  /** 
     219   * @see        AgaviAttributeHolder::setAttributesByRef() 
     220   * 
     221   * @author     David Zuelke <dz@bitxtender.com> 
     222   * @since      0.9.0 
     223   */ 
     224  public function & removeAttribute($name) 
     225  { 
     226    return $this->container->removeAttribute($name); 
     227  } 
     228   
     229  /** 
     230   * @see        AgaviAttributeHolder::setAttributesByRef() 
     231   * 
     232   * @author     David Zuelke <dz@bitxtender.com> 
     233   * @since      0.9.0 
     234   */ 
     235  public function setAttribute($name, $value) 
     236  { 
     237    $this->container->setAttribute($name, $value); 
     238  } 
     239 
     240  /** 
     241   * @see        AgaviAttributeHolder::setAttributesByRef() 
     242   * 
     243   * @author     David Zuelke <dz@bitxtender.com> 
     244   * @since      0.10.0 
     245   */ 
     246  public function appendAttribute($name, $value) 
     247  { 
     248    $this->container->appendAttribute($name, $value); 
     249  } 
     250 
     251  /** 
     252   * @see        AgaviAttributeHolder::setAttributesByRef() 
     253   * 
     254   * @author     David Zuelke <dz@bitxtender.com> 
     255   * @since      0.9.0 
     256   */ 
     257  public function setAttributeByRef($name, &$value) 
     258  { 
     259    $this->container->setAttributeByRef($name, $value); 
     260  } 
     261 
     262  /** 
     263   * @see        AgaviAttributeHolder::setAttributesByRef() 
     264   * 
     265   * @author     David Zuelke <dz@bitxtender.com> 
     266   * @since      0.10.0 
     267   */ 
     268  public function appendAttributeByRef($name, &$value) 
     269  { 
     270    $this->container->appendAttributeByRef($name, $value); 
     271  } 
     272 
     273  /** 
     274   * @see        AgaviAttributeHolder::setAttributesByRef() 
     275   * 
     276   * @author     David Zuelke <dz@bitxtender.com> 
     277   * @since      0.9.0 
     278   */ 
     279  public function setAttributes(array $attributes) 
     280  { 
     281    $this->container->setAttributes($attributes); 
     282  } 
     283 
     284  /** 
     285   * @see        AgaviAttributeHolder::setAttributesByRef() 
     286   * 
     287   * @author     David Zuelke <dz@bitxtender.com> 
     288   * @since      0.9.0 
     289   */ 
     290  public function setAttributesByRef(array &$attributes) 
     291  { 
     292    $this->container->setAttributesByRef($attributes); 
     293  } 
    150294} 
    151295 
  • branches/david-execution_flow/src/config/defaults/autoload.xml

    r1435 r1448  
    9898      <autoload name="AgaviIFilter">%core.agavi_dir%/filter/AgaviIFilter.interface.php</autoload> 
    9999      <autoload name="AgaviIGlobalFilter">%core.agavi_dir%/filter/AgaviIGlobalFilter.interface.php</autoload> 
    100       <autoload name="AgaviIRenderingFilter">%core.agavi_dir%/filter/AgaviIRenderingFilter.interface.php</autoload> 
    101100      <autoload name="AgaviISecurityFilter">%core.agavi_dir%/filter/AgaviISecurityFilter.interface.php</autoload> 
    102101      <autoload name="AgaviSecurityFilter">%core.agavi_dir%/filter/AgaviSecurityFilter.class.php</autoload> 
  • branches/david-execution_flow/src/config/defaults/compile.xml

    r1427 r1448  
    4545      <compile>%core.agavi_dir%/core/AgaviContext.class.php</compile> 
    4646      <compile>%core.agavi_dir%/controller/AgaviController.class.php</compile> 
     47      <compile>%core.agavi_dir%/controller/AgaviExecutionContainer.class.php</compile> 
    4748      <compile>%core.agavi_dir%/filter/AgaviFilter.class.php</compile> 
    4849      <compile>%core.agavi_dir%/filter/AgaviDispatchFilter.class.php</compile> 
  • branches/david-execution_flow/src/config/defaults/config_handlers.xml

    r1326 r1448  
    103103      <handler pattern="%core.config_dir%/global_filters.xml" validate="%core.agavi_dir%/config/xsd/filters.xsd" class="AgaviFilterConfigHandler" /> 
    104104 
    105       <handler pattern="%core.config_dir%/rendering_filters.xml" validate="%core.agavi_dir%/config/xsd/filters.xsd" class="AgaviFilterConfigHandler" /> 
    106  
    107105      <handler pattern="%core.config_dir%/output_types.xml" validate="%core.agavi_dir%/config/xsd/output_types.xsd" class="AgaviOutputTypeConfigHandler" /> 
    108106 
     
    134132      <handler pattern="%core.module_dir%/*/config/action_filters.xml" validate="%core.agavi_dir%/config/xsd/filters.xsd" class="AgaviFilterConfigHandler" /> 
    135133 
    136       <handler pattern="%core.module_dir%/*/config/rendering_filters.xml" validate="%core.agavi_dir%/config/xsd/filters.xsd" class="AgaviFilterConfigHandler" /> 
    137  
    138134      <handler pattern="%core.module_dir%/*/config/module.xml" validate="%core.agavi_dir%/config/xsd/module.xsd" class="AgaviModuleConfigHandler" /> 
    139135 
  • branches/david-execution_flow/src/controller/AgaviController.class.php

    r1236 r1448  
    3030{ 
    3131  /** 
     32   * @var        int The number of forward() calls done so far. 
     33   */ 
     34  protected $numForwards = 0; 
     35   
     36  /** 
    3237   * @var        int The maximum number of times this Controller will forward(). 
    3338   */ 
    3439  protected $maxForwards  = 20; 
    3540   
    36   /** 
    37    * @var        int The render mode, see AgaviView RENDER_* constants. 
    38    */ 
    39   protected $renderMode   = AgaviView::RENDER_CLIENT; 
    40  
    41   /** 
    42    * @var        AgaviActionStack An ActionStack instance. 
    43    */ 
    44   protected $actionStack = null; 
    45  
    4641  /** 
    4742   * @var        AgaviContext An AgaviContext instance. 
     
    5550    'global' => array(), 
    5651    'action' => array( 
    57       '*' => null 
    58     ), 
    59     'rendering' => array( 
    6052      '*' => null 
    6153    ), 
     
    7668   
    7769  /** 
    78    * @var        AgaviResponse The Response instance for this Controller. 
    79    */ 
    80   protected $response = null; 
    81    
    82   /** 
    83    * @var        AgaviResponse The Response to be used after redirects are set. 
    84    */ 
    85   protected $redirectResponse = null; 
    86  
    87   /** 
    88    * Retrieve the ActionStack. 
    89    * 
    90    * @return     AgaviActionStack the ActionStack instance 
    91    * 
    92    * @author     David Zuelke <dz@bitxtender.com> 
    93    * @since      0.11.0 
    94    */ 
    95   public function getActionStack() 
    96   { 
    97     return $this->actionStack; 
    98   } 
    99  
    100   /** 
    10170   * Indicates whether or not a module has a specific action. 
    10271   * 
     
    10473   * @param      string An action name. 
    10574   * 
    106    * @return     mixed  The actual name of the action (might be auto-resolved), 
    107    *                    or false if no Action related to that name was found. 
    108    * 
    109    * @author     Sean Kerr <skerr@mojavi.org> 
    110    * @author     David Zuelke <dz@bitxtender.com> 
    111    * @since      0.9.0 
    112    */ 
    113   public function actionExists($moduleName, $actionName = null) 
     75   * @return     mixed  The actual name of the action (might be auto-resolved). 
     76   * 
     77   * @throws     AgaviControllerException if the action could not be found. 
     78   * @author     Sean Kerr <skerr@mojavi.org> 
     79   * @author     David Zuelke <dz@bitxtender.com> 
     80   * @since      0.9.0 
     81   */ 
     82  public function resolveAction($moduleName, $actionName = null) 
    11483  { 
    11584    $actionName = str_replace('.', '/', $actionName); 
     
    12392      if(is_readable($file)) { 
    12493        return $actionName; 
    125       } else { 
    126         return false; 
    127       } 
    128     } 
     94      } 
     95    } 
     96    throw new AgaviControllerException(sprintf('Action "%s" in Module "%s" could not be found.', $actionName, $moduleName)); 
     97  } 
     98   
     99  public function incNumForwards() 
     100  { 
     101    if(++$this->numForwards > $this->maxForwards) { 
     102      throw new AgaviForwardException('Too many forwards have been detected for this request.'); 
     103    } 
     104  } 
     105   
     106  /** 
     107   * Create and initialize new execution container instance. 
     108   * 
     109   * @param      string The name of the module. 
     110   * @param      string The name of the action. 
     111   * @param      array  Optional additional parameters. 
     112   * 
     113   * @return     AgaviExecutionContainer A new execution container instance, 
     114   *                                     fully initialized. 
     115   * 
     116   * @author     David Zuelke <dz@bitxtender.com> 
     117   * @since      0.11.0 
     118   */ 
     119  public function createExecutionContainer($moduleName, $actionName, array $parameters = array()) 
     120  { 
     121    $container = new AgaviExecutionContainer(); 
     122    $container->initialize($this->context, $moduleName, $actionName, $parameters); 
     123    return $container; 
    129124  } 
    130125   
     
    146141      $request->setAttribute('matchedRoutes', $this->context->getRouting()->execute(), 'org.agavi.routing'); 
    147142     
    148       if($parameters != null) { 
    149         $request->setParametersByRef($parameters); 
    150       } 
     143      $request->setParameters($parameters); 
    151144     
    152145      // determine our module and action 
     
    171164      } 
    172165       
     166      $container = $this->createExecutionContainer($moduleName, $actionName); 
     167       
    173168      // create a new filter chain 
    174169      $fcfi = $this->context->getFactoryInfo('filter_chain'); 
    175170      $filterChain = new $fcfi['class'](); 
    176       $filterChain->initialize($this->response, $fcfi['parameters']); 
     171      $filterChain->initialize($this->context, $fcfi['parameters']); 
    177172       
    178173      $this->loadFilters($filterChain, 'global'); 
     
    182177     
    183178      // go, go, go! 
    184       $filterChain->execute(); 
    185        
    186       if($this->redirectResponse instanceof AgaviResponse) { 
    187         $this->redirectResponse->append($this->response->export()); 
    188         $this->redirectResponse->send(); 
     179      $filterChain->execute($container); 
     180       
     181      $container->getResponse()->send(); 
     182       
     183    } catch(Exception $e) { 
     184      if(isset($container) && $container instanceof AgaviExecutionContainer && $container->getResponse() instanceof AgaviResponse) { 
     185        AgaviException::printStackTrace($e, $this->context, $response); 
    189186      } else { 
    190         $this->response->send(); 
    191       } 
    192        
    193     } catch(Exception $e) { 
    194       AgaviException::printStackTrace($e, $this->context, $this->getResponse()); 
    195     } 
    196   } 
    197  
    198   /** 
    199    * Forward the request to another action. 
    200    * 
    201    * @param      string A module name. 
    202    * @param      string An action name. 
    203    * @param      array|AgaviParameterHolder Additional parameters which will be 
    204    *                                        passed to the action. 
    205    * 
    206    * @throws     <b>AgaviConfigurationException</b> If an invalid configuration  
    207    *                                                setting has been found. 
    208    * @throws     <b>AgaviForwardException</b> If an error occurs while  
    209    *                                          forwarding the request. 
    210    * @throws     <b>AgaviInitializationException</b> If the action could not be 
    211    *                                                 initialized. 
    212    * @throws     <b>AgaviSecurityException</b> If the action requires security  
    213    *                                           but the user implementation is  
    214    *                                           not of type SecurityUser. 
    215    * 
    216    * @author     Sean Kerr <skerr@mojavi.org> 
    217    * @since      0.9.0 
    218    */ 
    219   public function forward($moduleName, $actionName = 'Index', $additionalParams = array()) 
    220   { 
    221     $request = $this->context->getRequest(); 
    222  
    223     $actionName = str_replace('.', '/', $actionName); 
    224     $actionName = preg_replace('/[^a-z0-9\-_\/]+/i', '', $actionName); 
    225     $moduleName = preg_replace('/[^a-z0-9\-_]+/i', '', $moduleName); 
    226  
    227     if($this->actionStack->getSize() >= $this->maxForwards) { 
    228       throw new AgaviForwardException('Too many forwards have been detected for this request'); 
    229     } 
    230  
    231     if(!AgaviConfig::get('core.available', false)) { 
    232       // application is unavailable 
    233       $request->setAttributes(array( 
    234         'requested_module' => $moduleName, 
    235         'requested_action' => $actionName 
    236       ), 'org.agavi.controller.forwards.unavailable'); 
    237       $moduleName = AgaviConfig::get('actions.unavailable_module'); 
    238       $actionName = AgaviConfig::get('actions.unavailable_action'); 
    239  
    240       if(!$this->actionExists($moduleName, $actionName)) { 
    241         // cannot find unavailable module/action 
    242         $error = 'Invalid configuration settings: actions.unavailable_module "%s", actions.unavailable_action "%s"'; 
    243         $error = sprintf($error, $moduleName, $actionName); 
    244  
    245         throw new AgaviConfigurationException($error); 
    246       } 
    247  
    248     } elseif(!$this->actionExists($moduleName, $actionName)) { 
    249       // the requested action doesn't exist 
    250  
    251       // track the requested module so we have access to the data 
    252       // in the error 404 page 
    253       $request->setAttributes(array( 
    254         'requested_module' => $moduleName, 
    255         'requested_action' => $actionName 
    256       ), 'org.agavi.controller.forwards.error_404'); 
    257  
    258       // switch to error 404 action 
    259       $moduleName = AgaviConfig::get('actions.error_404_module'); 
    260       $actionName = AgaviConfig::get('actions.error_404_action'); 
    261  
    262       if(!$this->actionExists($moduleName, $actionName)) { 
    263         // cannot find unavailable module/action 
    264         $error = 'Invalid configuration settings: actions.error_404_module "%s", actions.error_404_action "%s"'; 
    265         $error = sprintf($error, $moduleName, $actionName); 
    266  
    267         throw new AgaviConfigurationException($error); 
    268       } 
    269     } 
    270      
    271     // get the "real" action name, i.e. allow auto-resolving of sub-action IndexActions 
    272     $actionName = $this->actionExists($moduleName, $actionName); 
    273  
    274     // create an instance of the action 
    275     $actionInstance = $this->getAction($moduleName, $actionName); 
    276  
    277     // add a new action stack entry 
    278     $actionEntry = $this->actionStack->addEntry($moduleName, $actionName, $actionInstance, new AgaviParameterHolder(array_merge($request->getParameters(), $additionalParams instanceof AgaviParameterHolder ? $additionalParams->getParameters() : (array) $additionalParams))); 
    279  
    280     // include the module configuration 
    281     // laoded only once due to the way import() works 
    282     if(is_readable(AgaviConfig::get('core.module_dir') . '/' . $moduleName . '/config/module.xml')) { 
    283       AgaviConfigCache::import(AgaviConfig::get('core.module_dir') . '/' . $moduleName . '/config/module.xml', $this->context->getName()); 
    284     } else { 
    285       AgaviConfig::set('modules.' . strtolower($moduleName) . '.enabled', true); 
    286     } 
    287  
    288     // save autoloads so we can restore them later 
    289     $oldAutoloads = Agavi::$autoloads; 
    290      
    291     static $moduleAutoloads = array(); 
    292     if(!isset($moduleAutoloads[$moduleName])) { 
    293       $moduleAutoloads[$moduleName] = array(); 
    294       $moduleAutoload = AgaviConfig::get('core.module_dir') . '/' . $moduleName . '/config/autoload.xml'; 
    295       if(is_readable($moduleAutoload)) { 
    296         include(AgaviConfigCache::checkConfig($moduleAutoload)); 
    297         $moduleAutoloads[$moduleName] = Agavi::$autoloads; 
    298       } 
    299     } else { 
    300       Agavi::$autoloads = array_merge($moduleAutoloads[$moduleName], Agavi::$autoloads); 
    301     } 
    302      
    303     if(AgaviConfig::get('modules.' . strtolower($moduleName) . '.enabled')) { 
    304       // check for a module config.php 
    305       $moduleConfig = AgaviConfig::get('core.module_dir') . '/' . $moduleName . '/config.php'; 
    306       if(is_readable($moduleConfig)) { 
    307         require_once($moduleConfig); 
    308       } 
    309  
    310       // initialize the action 
    311       $actionInstance->initialize($this->context); 
    312        
    313       // create a new response instance for this action 
    314       $rfi = $this->context->getFactoryInfo('response'); 
    315       $response = new $rfi['class']; 
    316       $response->initialize($this->context, $rfi['parameters']); 
    317  
    318       // create a new filter chain 
    319       $fcfi = $this->context->getFactoryInfo('filter_chain'); 
    320       $filterChain = new $fcfi['class'](); 
    321       $filterChain->initialize($response, $fcfi['parameters']); 
    322  
    323       if(AgaviConfig::get('core.available', false)) { 
    324         // the application is available so we'll register 
    325         // global and module filters, otherwise skip them 
    326  
    327         // does this action require security? 
    328         if(AgaviConfig::get('core.use_security', false) && $actionInstance->isSecure()) { 
    329           // register security filter 
    330           $filterChain->register($this->filters['security']); 
    331         } 
    332  
    333         // load filters 
    334         $this->loadFilters($filterChain, 'action'); 
    335         $this->loadFilters($filterChain, 'action', $moduleName); 
    336       } 
    337  
    338       // register the execution filter 
    339       $filterChain->register($this->filters['execution']); 
    340  
    341       // process the filter chain 
    342       $filterChain->execute(); 
    343        
    344       // clear the global request attribute namespace containing attributes for the View 
    345       $request->removeAttributeNamespace($request->getDefaultNamespace()); 
    346        
    347       if($this->renderMode == AgaviView::RENDER_CLIENT && !$actionEntry->hasNext()) { 
    348         // add the output for this action to the global one 
    349         $this->getResponse()->append($response->export()); 
    350       } 
    351        
    352       // restore autoloads 
    353       Agavi::$autoloads = $oldAutoloads; 
    354  
    355     } else { 
    356       // module is disabled 
    357       $request->setAttributes(array( 
    358         'requested_module' => $moduleName, 
    359         'requested_action' => $actionName 
    360       ), 'org.agavi.controller.forwards.disabled'); 
    361       $moduleName = AgaviConfig::get('actions.module_disabled_module'); 
    362       $actionName = AgaviConfig::get('actions.module_disabled_action'); 
    363  
    364       if(!$this->actionExists($moduleName, $actionName)) { 
    365         // cannot find mod disabled module/action 
    366         $error = 'Invalid configuration settings: actions.module_disabled_module "%s", actions.module_disabled_action "%s"'; 
    367         $error = sprintf($error, $moduleName, $actionName); 
    368         throw new AgaviConfigurationException($error); 
    369       } 
    370  
    371       $this->forward($moduleName, $actionName); 
    372     } 
    373      
    374     if($actionEntry->hasNext()) { 
    375       $next = $actionEntry->getNext(); 
    376       $request->setParameters($next['parameters'] instanceof AgaviParameterHolder ? $next['parameters']->getParameters() : $next['parameters']); 
    377       $this->forward($next['moduleName'], $next['actionName']); 
     187        AgaviException::printStackTrace($e, $this->context); 
     188      } 
    378189    } 
    379190  } 
     
    391202   */ 
    392203  abstract public function redirect($to); 
    393  
    394   /** 
    395    * Retrieve the currently executing Action's name. 
    396    * 
    397    * @return     string The currently executing action name, if one is set, 
    398    *                    otherwise null.