Changeset 1477

Show
Ignore:
Timestamp:
01/10/07 13:48:36 (2 years ago)
Author:
david
Message:

more work on execution flow changes, next works now again, security filter forwards etc have been figured out. we still have to eliminate some of the wonkiness with the global response, that's gonna be rather difficult, I imagine. refs #373

Location:
branches/david-execution_flow
Files:
11 modified

Legend:

Unmodified
Added
Removed
  • branches/david-execution_flow/src/config/AgaviOutputTypeConfigHandler.class.php

    r1475 r1477  
    101101      $code[] = implode("\n", array( 
    102102        '$ot = new AgaviOutputType();', 
    103         '$ot->initialize($this->context, ' . var_export($outputType['parameters'], true) . ', ' . var_export($outputType['renderers'], true) . ', ' . var_export($outputType['default_renderer'], true) . ', ' . var_export($outputType['exception_template'], true) . ');', 
     103        '$ot->initialize($this->context, ' . var_export($outputType['parameters'], true) . ', ' . var_export($outputTypeName, true) . ', ' . var_export($outputType['renderers'], true) . ', ' . var_export($outputType['default_renderer'], true) . ', ' . var_export($outputType['exception_template'], true) . ');', 
    104104        '$this->outputTypes["' . $outputTypeName . '"] = $ot;', 
    105105      )); 
  • branches/david-execution_flow/src/controller/AgaviController.class.php

    r1475 r1477  
    8888    } else { 
    8989      // maybe it's a sub-action with the last portion omitted 
    90       $actionName .= '/Index'; 
     90      $actionName .= ($actionName == '' ? '' : '/') . 'Index'; 
    9191      $file = AgaviConfig::get('core.module_dir') . '/' . $moduleName . '/actions/' . $actionName . 'Action.class.php'; 
    9292      if(is_readable($file)) { 
     
    126126   * @since      0.11.0 
    127127   */ 
    128   public function createExecutionContainer($moduleName, $actionName, array $parameters = array()) 
     128  public function createExecutionContainer($moduleName = null, $actionName = null, array $parameters = array()) 
    129129  { 
    130130    // create a new filter chain 
     
    152152      $request = $this->context->getRequest(); 
    153153       
    154       // match routes and set matched routes as request attributes 
    155       $request->setAttribute('matchedRoutes', $this->context->getRouting()->execute(), 'org.agavi.routing'); 
    156      
    157154      $request->setParameters($parameters); 
    158      
    159       // determine our module and action 
    160       $moduleName = $request->getParameter($request->getModuleAccessor()); 
    161       $actionName = $request->getParameter($request->getActionAccessor()); 
    162      
     155       
     156      // match routes and assign returned initial execution container 
     157      $container = $this->context->getRouting()->execute(); 
     158       
     159      $moduleName = $container->getModuleName(); 
     160      $actionName = $container->getActionName(); 
     161       
    163162      if($moduleName == null) { 
    164163        // no module has been specified 
    165         $moduleName = AgaviConfig::get('actions.default_module'); 
    166         $request->setParameter($request->getModuleAccessor(), $moduleName); 
    167       } 
    168       if($actionName == null) { 
    169         // no action has been specified 
    170         if($this->actionExists($moduleName, 'Index')) { 
    171           // an Index action exists 
    172           $actionName = 'Index'; 
    173         } else { 
    174           // use the default action 
    175           $actionName = AgaviConfig::get('actions.default_action'); 
    176         } 
    177         $request->setParameter($request->getActionAccessor(), $actionName); 
    178       } 
    179        
    180       $container = $this->createExecutionContainer($moduleName, $actionName); 
     164        $container->setModuleName(AgaviConfig::get('actions.default_module')); 
     165        $container->setActionName(AgaviConfig::get('actions.default_action')); 
     166      } 
    181167       
    182168      // create a new filter chain 
     
    186172       
    187173      $this->loadFilters($filterChain, 'global'); 
    188      
     174       
    189175      // register the dispatch filter 
    190176      $filterChain->register($this->filters['dispatch']); 
    191      
     177       
    192178      // go, go, go! 
    193179      $filterChain->execute($container); 
     
    196182       
    197183    } catch(Exception $e) { 
    198       if(isset($container) && $container instanceof AgaviExecutionContainer && ($response = $container->getResponse()) instanceof AgaviResponse) { 
    199         AgaviException::printStackTrace($e, $this->context, $response); 
     184      if(isset($container) && $container instanceof AgaviExecutionContainer) { 
     185        AgaviException::printStackTrace($e, $this->context, $container); 
    200186      } else { 
    201187        AgaviException::printStackTrace($e, $this->context); 
     
    231217   * @since      0.9.0 
    232218   */ 
    233   public function getAction($moduleName, $actionName) 
     219  public function createActionInstance($moduleName, $actionName) 
    234220  { 
    235221    static $loaded = array(); 
     
    293279   * @since      0.9.0 
    294280   */ 
    295   public function getView($moduleName, $viewName) 
     281  public function createViewInstance($moduleName, $viewName) 
    296282  { 
    297283    static $loaded; 
     
    340326  public function initialize(AgaviResponse $response, array $parameters = array()) 
    341327  { 
    342     $this->maxForwards = isset($parameters['max_fowards']) ? $parameters['max_forwards'] : 20; 
     328    $this->maxExecutions = isset($parameters['max_executions']) ? $parameters['max_executions'] : 20; 
    343329     
    344330    $this->response = $response; 
  • branches/david-execution_flow/src/controller/AgaviExecutionContainer.class.php

    r1475 r1477  
    1515 
    1616/** 
    17  * A container used for each forward() call that holds action information, the 
    18  * response etc. 
     17 * A container used for each action execution that holds neecessary information, 
     18 * such as the output type, the response etc. 
    1919 *  
    2020 * @package    agavi 
     
    7575   
    7676  /** 
     77   * @var        AgaviExecutionContainer The next container to execute. 
     78   */ 
     79  protected $next = null; 
     80   
     81  /** 
    7782   * Initialize the container. This will create a response instance. 
    7883   * 
     
    101106   * 
    102107   * This will create an instance of the action and merge in request parameters. 
     108   * 
     109   * This method returns a response. It is not necessarily the same response as 
     110   * the one of this container, but instead the one that contains the actual 
     111   * content that should be used for output etc, since the container's own 
     112   * response might be empty or invalid due to a "next" container that has been 
     113   * set and executed. 
     114   * 
     115   * @return     AgaviResponse The "real" response. 
    103116   * 
    104117   * @author     David Zuelke <dz@bitxtender.com> 
     
    164177    $this->setActionName($actionName); 
    165178     
    166     $this->actionInstance = $controller->getAction($this->moduleName, $this->actionName); 
     179    $this->actionInstance = $controller->createActionInstance($this->moduleName, $this->actionName); 
    167180     
    168181    // include the module configuration 
     
    250263       
    251264      // TODO. this will be pretty difficult, I guess... 
    252       $controller->forward($moduleName, $actionName); 
     265      $this->setNext($controller->createExecutionContainer($moduleName, $actionName)); 
    253266    } 
     267     
     268    if($this->next !== null) { 
     269      return $this->next->execute(); 
     270    } else { 
     271      return $this->getResponse(); 
     272    } 
    254273  } 
    255274   
     
    268287   
    269288  /** 
    270    * Retrieve this container's rendered view presentation. 
     289   * Retrieve this container's response instance. 
    271290   * 
    272291   * @return     AgaviResponse The Response instance for this action. 
     
    281300   
    282301  /** 
     302   * Set a new response. 
     303   * 
     304   * @param      AgaviResponse A new Response instance. 
     305   * 
     306   * @author     David Zuelke <dz@bitxtender.com> 
     307   * @since      0.11.0 
     308   */ 
     309  public function setResponse(AgaviResponse $response) 
     310  { 
     311    $this->response = $response; 
     312  } 
     313   
     314  /** 
    283315   * Retrieve the output type of this container. 
    284316   * 
     
    291323  { 
    292324    return $this->outputType; 
     325  } 
     326   
     327  /** 
     328   * Set a different output type for this container. 
     329   * 
     330   * @param      AgaviOutputType An output type object. 
     331   * 
     332   * @author     David Zuelke <dz@bitxtender.com> 
     333   * @since      0.11.0 
     334   */ 
     335  public function setOutputType(AgaviOutputType $outputType) 
     336  { 
     337    $this->outputType = $outputType; 
    293338  } 
    294339   
     
    424469    $this->viewName = $viewName; 
    425470  } 
     471   
     472   /** 
     473   * Check if a "next" container has been set. 
     474   * 
     475   * @return     bool True, if a container for eventual execution has been set. 
     476   * 
     477   * @author     David Zuelke <dz@bitxtender.com> 
     478   * @since      0.11.0 
     479   */ 
     480  public function hasNext() 
     481  { 
     482    return $this->next !== null; 
     483  } 
     484   
     485  /** 
     486   * Get the "next" container. 
     487   * 
     488   * @return     AgaviExecutionContainer The "next" container, of null if unset. 
     489   * 
     490   * @author     David Zuelke <dz@bitxtender.com> 
     491   * @since      0.11.0 
     492   */ 
     493  public function getNext() 
     494  { 
     495    return $this->next; 
     496  } 
     497   
     498  /** 
     499   * Set the container that should be executed once this one finished running. 
     500   * 
     501   * @param      AgaviExcecutionContainer An execution container instance. 
     502   * 
     503   * @author     David Zuelke <dz@bitxtender.com> 
     504   * @since      0.11.0 
     505   */ 
     506  public function setNext(AgaviExecutionContainer $container) 
     507  { 
     508    $this->next = $container; 
     509  } 
     510   
     511  /** 
     512   * Remove a possibly set "next" container. 
     513   * 
     514   * @return     AgaviExecutionContainer The removed "next" container, or null 
     515   *                                     if none had been set. 
     516   * 
     517   * @author     David Zuelke <dz@bitxtender.com> 
     518   * @since      0.11.0 
     519   */ 
     520  public function clearNext() 
     521  { 
     522    $retval = $this->next; 
     523    $this->next = null; 
     524    return $retval; 
     525  } 
    426526} 
    427527 
  • branches/david-execution_flow/src/controller/AgaviOutputType.class.php

    r1475 r1477  
    6262   * @since      0.11.0 
    6363   */ 
    64   public function initialize(AgaviContext $context, array $parameters, array $renderers, $defaultRenderer, $exceptionTemplate = null) 
     64  public function initialize(AgaviContext $context, array $parameters, $name, array $renderers, $defaultRenderer, $exceptionTemplate = null) 
    6565  { 
    6666    $this->context = $context; 
    6767     
    6868    $this->parameters = $parameters; 
     69     
     70    $this->name = $name; 
    6971     
    7072    $this->renderers = $renderers; 
  • branches/david-execution_flow/src/core/AgaviContext.class.php

    r1456 r1477  
    213213        $profile = AgaviConfig::get('core.default_context'); 
    214214        if($profile === null) { 
    215           throw new AgaviException('You must supply an environment name to AgaviContext::getInstance() or set the name of the default environment to be used in the configuration directive "core.default_context".'); 
     215          throw new AgaviException('You must supply a context name to AgaviContext::getInstance() or set the name of the default context to be used in the configuration directive "core.default_context".'); 
    216216        } 
    217217      } 
     
    262262    $this->name = $profile; 
    263263     
    264     include(AgaviConfigCache::checkConfig(AgaviConfig::get('core.config_dir') . '/factories.xml', $profile)); 
     264    try { 
     265      include(AgaviConfigCache::checkConfig(AgaviConfig::get('core.config_dir') . '/factories.xml', $profile)); 
     266    } catch(Exception $e) { 
     267      AgaviException::printStackTrace($e, $this); 
     268    } 
    265269     
    266270    register_shutdown_function(array($this, 'shutdown')); 
  • branches/david-execution_flow/src/exception/AgaviException.class.php

    r1436 r1477  
    4343   * @since      0.9.0 
    4444   */ 
    45   public static function printStackTrace(Exception $e, AgaviContext $context = null, AgaviResponse $response = null) 
     45  public static function printStackTrace(Exception $e, AgaviContext $context = null, AgaviExecutionContainer $container = null) 
    4646  { 
    4747    // discard any previous output waiting in the buffer 
    4848    while(@ob_end_clean()); 
    4949     
    50     // throw away any response data that might be there 
    51     if($context !== null && ($c = $context->getController()) !== null && $response !== null) { 
    52       if($response->isLocked()) { 
    53         // reponse is locked, so grab the output and discard it 
    54         ob_start(); 
    55         $response->send(); 
    56         ob_end_clean(); 
    57       } else { 
    58         // not locked, we can clear the response 
    59         $response->clear(); 
    60       } 
    61     } 
    62      
    63     if($context !== null && ($c = $context->getController()) !== null && ($oti = $c->getOutputTypeInfo()) !== null && isset($oti['exception_template'])) {  
    64       // an exception template was defined for this output type 
    65       include($oti['exception_template']);  
     50    if($context !== null && $container !== null && ($et = $container->getExceptionTemplate()) !== null) {  
     51      // an exception template was defined for the container's output type 
     52      include($et);  
     53    } elseif($container === null && ($c = $context->getController()) !== null && ($ot = $c->getOutputType() !== null) && ($et = $ot->getExceptionTemplate()) !== null) { 
     54      // an exception template was defined for the default output type and no container was given 
     55      include($et); 
    6656    } elseif($context !== null && $tpl = AgaviConfig::get('exception.templates.' . $context->getName())) { 
    6757      // a template was set for this context 
  • branches/david-execution_flow/src/filter/AgaviDispatchFilter.class.php

    r1454 r1477  
    4646  public function execute(AgaviFilterChain $filterChain, AgaviExecutionContainer $container) 
    4747  { 
    48     $container->execute(); 
     48    $container->setResponse($container->execute()); 
    4949  } 
    5050} 
  • branches/david-execution_flow/src/filter/AgaviExecutionFilter.class.php

    r1475 r1477  
    333333 
    334334      // get the view instance 
    335       $viewInstance = $controller->getView($viewModule, $viewName); 
     335      $viewInstance = $controller->createViewInstance($viewModule, $viewName); 
    336336 
    337337      // initialize the view 
     
    363363        } 
    364364        $key = $request->toggleLock(); 
    365         $renderer = $viewInstance->$executeMethod($container); 
     365        $next = $viewInstance->$executeMethod($container); 
    366366        $request->toggleLock($key); 
    367367         
    368         $attributes =& $viewInstance->getAttributes(); 
    369          
    370         $output = array(); 
    371         $nextOutput = null; 
    372         foreach($viewInstance->getLayers() as $layerName => $layer) { 
    373           foreach($layer->getSlots() as $slotName => $slotContainer) { 
    374             $slotContainer->execute(); 
    375             $response = $slotContainer->getResponse(); 
    376             if($response) { 
    377               // set the presentation data as a template attribute 
    378               $output[$name] = $response->getContent(); 
    379               // $response->merge($response->exportInfo()); 
    380             } else { 
    381               $output[$name] = null; 
     368        if($next instanceof AgaviExecutionContainer) { 
     369          $container->setNext($next); 
     370        } else { 
     371          $attributes =& $viewInstance->getAttributes(); 
     372 
     373          $output = array(); 
     374          $nextOutput = null; 
     375          foreach($viewInstance->getLayers() as $layerName => $layer) { 
     376            foreach($layer->getSlots() as $slotName => $slotContainer) { 
     377              $slotResponse = $slotContainer->execute(); 
     378              if($response) { 
     379                // set the presentation data as a template attribute 
     380                $output[$name] = $slotResponse->getContent(); 
     381                // $response->merge($response->exportInfo()); 
     382              } else { 
     383                $output[$name] = null; 
     384              } 
    382385            } 
     386            $nextOutput = $layer->getRenderer()->render($layer, $attributes, $output); 
     387            $output = array(); 
     388            $output[$layerName] = $nextOutput; 
    383389          } 
    384           $nextOutput = $layer->getRenderer()->render($layer, $attributes, $output); 
    385           $output = array(); 
    386           $output[$layerName] = $nextOutput; 
    387         } 
    388         $response->setContent($nextOutput); 
     390          $response->setContent($nextOutput); 
     391        } 
    389392      } 
    390393 
     
    527530    } 
    528531 
    529     if($viewName !== AgaviView::NONE && !$controller->viewExists($viewModule, $viewName)) { 
    530       // the requested view doesn't exist 
    531       $file = AgaviConfig::get('core.module_dir') . '/' . $viewModule . '/views/' . $viewName . 'View.class.php'; 
    532       $error = 'Module "%s" does not contain the view "%sView" or the file "%s" is unreadable'; 
    533       $error = sprintf($error, $viewModule, $viewName, $file); 
    534       throw new AgaviViewException($error); 
    535     } 
    536  
    537532    return array($viewModule, $viewName); 
    538533  } 
  • branches/david-execution_flow/src/filter/AgaviSecurityFilter.class.php

    r1454 r1477  
    7070        $filterChain->execute($container); 
    7171      } else { 
    72         // the user doesn't have access, exit stage left 
     72        // the user doesn't have access, set info regarding next action and leave 
    7373        $request->setAttributes(array( 
    7474          'requested_module' => $container->getModuleName(), 
    7575          'requested_action' => $container->getActionName() 
    7676        ), 'org.agavi.controller.forwards.secure'); 
    77         $controller->forward(new AgaviExecutionContainer(AgaviConfig::get('actions.secure_module'), AgaviConfig::get('actions.secure_action'))); 
     77        $container->setNext($controller->createExecutionContainer(AgaviConfig::get('actions.secure_module'), AgaviConfig::get('actions.secure_action'))); 
    7878      } 
    7979 
     
    8484        'requested_action' => $container->getActionName() 
    8585      ), 'org.agavi.controller.forwards.login'); 
    86       $controller->forward(new AgaviExecutionContainer(AgaviConfig::get('actions.login_module'), AgaviConfig::get('actions.login_action'))); 
     86      $container->setNext($controller->createExecutionContainer(AgaviConfig::get('actions.login_module'), AgaviConfig::get('actions.login_action'))); 
    8787    } 
    8888  } 
  • branches/david-execution_flow/src/routing/AgaviRouting.class.php

    r1410 r1477  
    483483  public function execute() 
    484484  { 
     485    $req = $this->context->getRequest(); 
     486 
     487    $container = $this->context->getController()->createExecutionContainer(); 
     488    $response = $container->getResponse(); 
     489     
     490    if(!AgaviConfig::get('core.use_routing', false) || count($this->routes) == 0) { 
     491      // routing disabled, determine module and action manually and bail out 
     492      $container->setModuleName($req->getParameter($req->getModuleAccessor())); 
     493      $container->setActionName($req->getParameter($req->getActionAccessor())); 
     494       
     495      return $container; 
     496    } 
     497 
    485498    $matchedRoutes = array(); 
    486  
    487     if(!AgaviConfig::get('core.use_routing', false) || count($this->routes) == 0) { 
    488       // routing disabled, bail out 
    489       return $matchedRoutes; 
    490     } 
    491  
    492     $req = $this->context->getRequest(); 
    493499 
    494500    $input = $this->input; 
     
    501507    $aa = $req->getActionAccessor(); 
    502508    $requestMethod = $req->getMethod(); 
    503  
    504 //    $routes = array_keys($this->routes); 
    505509 
    506510    // get all top level routes 
     
    524528            $cb = $opts['callback']; 
    525529            $route['cb'] = new $cb(); 
    526             $route['cb']->initialize($this->response, $route); 
     530            $route['cb']->initialize($response, $route); 
    527531          } 
    528532 
     
    635639    // set the output type if necessary 
    636640    if($ot !== null) { 
    637       $this->context->getController()->setOutputType($ot); 
     641      $container->setOutputType($ot); 
    638642    } 
    639643 
     
    658662      )); 
    659663    } 
     664     
     665    $container->setModuleName($req->getParameter($ma)); 
     666    $container->setActionName($req->getParameter($aa)); 
     667     
     668    // set the list of matched route names as a request attribute 
     669    $req->setAttribute('matchedRoutes', $matchedRoutes, 'org.agavi.routing'); 
     670     
    660671    // return a list of matched route names 
    661     return $matchedRoutes; 
     672    return $container; 
    662673  } 
    663674 
  • branches/david-execution_flow/tests2/controller/ControllerTest.php

    r1457 r1477  
    5353    // TODO: check all other existing naming schemes for actions 
    5454 
    55     $action = $this->_controller->getAction('Test', 'Test'); 
     55    $action = $this->_controller->createActionInstance('Test', 'Test'); 
    5656    $this->assertType('Test_TestAction', $action); 
    5757    $this->assertType('AgaviAction', $action); 
    5858 
    5959    // TODO: this needs checking for errors  
    60 //    $this->_controller->getAction('Test', 'NonExistant'); 
     60//    $this->_controller->createActionInstance('Test', 'NonExistant'); 
    6161  } 
    6262