[Beeframework-svn] SF.net SVN: beeframework:[122] trunk/framework/Bee/MVC
Brought to you by:
b_hartmann,
m_plomer
From: <m_p...@us...> - 2013-11-07 17:11:42
|
Revision: 122 http://sourceforge.net/p/beeframework/code/122 Author: m_plomer Date: 2013-11-07 17:11:37 +0000 (Thu, 07 Nov 2013) Log Message: ----------- - MVC: Dispatcher: fixed interceptor resolution on handler exception - MVC: Dispatcher: added logging for some cases Modified Paths: -------------- trunk/framework/Bee/MVC/Dispatcher.php trunk/framework/Bee/MVC/HandlerExecutionChain.php trunk/framework/Bee/MVC/HandlerMapping/Abstract.php trunk/framework/Bee/MVC/IHandlerMapping.php Modified: trunk/framework/Bee/MVC/Dispatcher.php =================================================================== --- trunk/framework/Bee/MVC/Dispatcher.php 2013-11-06 12:36:06 UTC (rev 121) +++ trunk/framework/Bee/MVC/Dispatcher.php 2013-11-07 17:11:37 UTC (rev 122) @@ -26,30 +26,45 @@ * controller bean for the curret request.</li> * <li><b>viewResolver</b>: an instance of <code>Bee_MVC_IViewResolver</code> that is used to map view names returned by the back * controllers to actual view implementations.</li> - * </ul> + * </ul> * <p/> * Conceptually, this Dispatcher is based entirely on the implementation of the DispathcerServler in the * {@link http://www.springframework.org Spring Framework}. - * For additional information on the concepts, please refer to the chapter on Web MVC in the Spring documentation. - * + * For additional information on the concepts, please refer to the chapter on Web MVC in the Spring documentation. + * * @see Bee_IContext * @see Bee_MVC_IHandlerMapping * @see Bee_MVC_IViewResolver - * + * * @author Michael Plomer <mic...@it...> * @author Benjamin Hartmann */ class Bee_MVC_Dispatcher implements Bee_MVC_IFilterChain { - + const HANDLER_MAPPING_BEAN_NAME = 'handlerMapping'; - + const VIEW_RESOLVER_BEAN_NAME = 'viewResolver'; - + const FILTER_CHAIN_PROXY_NAME = 'filterChainProxy'; - + const HANDLER_EXCEPTION_RESOLVER_NAME = 'handlerExceptionResolver'; - + /** + * @var Logger + */ + protected $log; + + /** + * @return Logger + */ + protected function getLog() { + if (!$this->log) { + $this->log = Logger::getLogger(get_class($this)); + } + return $this->log; + } + + /** * The dispatcher responsible for the current request * * @var Bee_MVC_Dispatcher @@ -60,30 +75,30 @@ * @var Bee_MVC_IHttpRequest */ private static $currentRequest = null; - + /** * The root context used by this dispatcher * * @var Bee_IContext */ private $context; - - + + /** * The handler mapping used by this dispatcher * * @var Bee_MVC_IHandlerMapping */ private $handlerMapping; - + /** * The view resolver used by this dispatcher * * @var Bee_MVC_IViewResolver */ private $viewResolver; - + /** * Enter description here... * @@ -92,7 +107,7 @@ private $filterChainProxy; /** - * + * * @var Bee_MVC_IHandlerExceptionResolver */ private $handlerExceptionResolver; @@ -108,10 +123,11 @@ } /** + * @throws Bee_Exceptions_Base * @return Bee_MVC_IHttpRequest */ public static function getCurrentRequest() { - if(is_null(self::$currentRequest)) { + if (is_null(self::$currentRequest)) { throw new Bee_Exceptions_Base('No request object constructed yet'); } @@ -120,25 +136,25 @@ /** * Allows to dispatch control to sub-controllers from within a current request. Intended to be used to include hierarchical structures - * which must be also available as first-class handlers (e.g. for AJAX-based updates). + * which must be also available as first-class handlers (e.g. for AJAX-based updates). * * @param Bee_MVC_IHttpRequest $request * @return void */ - public static function includeDispatch(Bee_MVC_IHttpRequest $request) { + public static function includeDispatch(Bee_MVC_IHttpRequest $request) { Bee_Utils_Assert::notNull(self::$currentDispatcher, 'No current dispatcher set - create an instance of Bee_MVC_Dispatcher and use its \'dispatch()\' method instead of \'includeDispatch()\''); Bee_Utils_Assert::notNull($request, 'Request object must not be null'); - + // @todo: maybe use the apache-only virtual() function if available? self::$currentDispatcher->dispatchInternally($request); } - + /** - * + * * @throws Bee_Context_NoSuchBeanDefinitionException * @throws Bee_Context_BeanNotOfRequiredTypeException * @throws Bee_Context_BeansException - * + * * @param String $beanName * @param String $requiredType * @return Object @@ -146,7 +162,7 @@ public static function getBeanFromDispatcherContext($beanName, $requiredType = null) { return self::get()->getContext()->getBean($beanName, $requiredType); } - + /** * Construct a new dispatcher based on the given context. * @@ -154,10 +170,10 @@ */ public function __construct(Bee_IContext $context) { $this->context = $context; - $this->init(); + $this->init(); } - + /** * Initializes this dispatcher. * @@ -170,16 +186,17 @@ try { $this->filterChainProxy = $this->context->getBean(self::FILTER_CHAIN_PROXY_NAME, 'Bee_MVC_IFilter'); } catch (Bee_Context_NoSuchBeanDefinitionException $ex) { - // @todo: log on INFO level: no filter chain proxy + $this->getLog()->info('no filter chain proxy configured'); } try { - $this->handlerExceptionResolver = $this->context->getBean(self::HANDLER_EXCEPTION_RESOLVER_NAME, 'Bee_MVC_IHandlerExceptionResolver'); + $this->handlerExceptionResolver = $this->context->getBean(self::HANDLER_EXCEPTION_RESOLVER_NAME, 'Bee_MVC_IHandlerExceptionResolver'); } catch (Bee_Context_NoSuchBeanDefinitionException $ex) { - // @todo: log on INFO level: no exception resolver + $this->getLog()->info('no exception resolver configured'); } - if($this->context->containsBean(Bee_MVC_Session_DispatcherAdapter::SESSION_HANDLER_NAME)) { + if ($this->context->containsBean(Bee_MVC_Session_DispatcherAdapter::SESSION_HANDLER_NAME)) { + $this->getLog()->info('custom session handler configured, setting it as PHP session_set_save_handler()'); $sessionAdapter = new Bee_MVC_Session_DispatcherAdapter($this->context); session_set_save_handler( array(&$sessionAdapter, "open"), @@ -191,15 +208,15 @@ ); } } - + /** - * + * * @return Bee_IContext */ protected function getContext() { return $this->context; } - + /** * Main dispatch method. Entry point into the whole request lifecycle of Bee MVC. * @@ -209,7 +226,7 @@ self::$currentDispatcher = $this; self::$currentRequest = $this->buildRequestObject(); - if(!is_null($this->filterChainProxy)) { + if (!is_null($this->filterChainProxy)) { $this->filterChainProxy->doFilter(self::$currentRequest, $this); } else { $this->doFilter(self::$currentRequest); @@ -219,51 +236,62 @@ } public function doFilter(Bee_MVC_IHttpRequest $request) { - $this->dispatchInternally($request); + $this->dispatchInternally($request); } - + private function dispatchInternally(Bee_MVC_IHttpRequest $request) { $handler = null; try { $mav = null; + $interceptors = array(); + $handlerException = null; try { - + $mappedHandler = $this->handlerMapping->getHandler($request); $interceptors = $mappedHandler->getInterceptors(); $handler = $mappedHandler->getHandler(); - - $interceptorIndex = -1; - - $interceptors_length = count($interceptors); - for ($i = 0; $i < $interceptors_length; $i++) { + +// $interceptorIndex = -1; + + for ($i = 0; $i < count($interceptors); $i++) { $interceptor = $interceptors[$i]; if (!$interceptor->preHandle($request, $handler)) { - // $this->triggerAfterCompletion($handler, $interceptorIndex, $request, null); + // $this->triggerAfterCompletion($handler, $interceptorIndex, $request, null); return; } - $interceptorIndex = $i; +// $interceptorIndex = $i; } - + // @todo: introduce HandlerAdapter $mav = $handler->handleRequest($request); - - } catch(Exception $e) { + + } catch (Exception $e) { + $this->getLog()->warn('handler or interceptor exception caught, trying to resolve appropriate error view', $e); // @todo: handle exceptions caused by handlers properly (i.e. as application level exceptions) - if($this->handlerExceptionResolver) { + if ($this->handlerExceptionResolver) { $mav = $this->handlerExceptionResolver->resolveException($request, $handler, $e); } - - if(!$mav) { + + if (!$mav) { throw $e; } + + // got a view, make sure the rest of the request processing runs as intended (esp. post-handling) + $handlerException = $e; } - if($mav instanceof Bee_MVC_ModelAndView) { + if ($mav instanceof Bee_MVC_ModelAndView) { $mav->addModelValue(Bee_MVC_Model::CURRENT_REQUEST_KEY, $request); $this->resolveModelAndView($mav); + if(!is_null($handlerException) && !count($interceptors)) { + // We were unable to resolve a handler and its interceptors due to an exception being thrown along + // the way, but we have an error view. Assume the error view needs the interceptor post-handlers to + // run normally: fetch list of configured interceptors from handler mapping directly. + $interceptors = $this->handlerMapping->getInterceptors(); + } // Apply postHandle methods of registered interceptors. - for ($i = $interceptors_length - 1; $i >= 0; $i--) { + for ($i = count($interceptors) - 1; $i >= 0; $i--) { $interceptor = $interceptors[$i]; $interceptor->postHandle($request, $handler, $mav); } @@ -274,13 +302,13 @@ throw $e; } } - + public function resolveModelAndView(Bee_MVC_ModelAndView $mav) { $resolvedView = $this->viewResolver->resolveViewName($mav->getViewName()); $mav->setResolvedView($resolvedView); - if($resolvedView instanceof Bee_MVC_View_Abstract) { + if ($resolvedView instanceof Bee_MVC_View_Abstract) { $statics = $resolvedView->getStaticAttributes(); - if(!$statics) { + if (!$statics) { $statics = array(); } $model = array_merge($statics, $mav->getModel()); @@ -288,21 +316,21 @@ } $this->resolveModelInternals($mav->getModel()); } - + private function resolveModelInternals(array $model) { foreach ($model as $modelElem) { - if($modelElem instanceof Bee_MVC_ModelAndView) { + if ($modelElem instanceof Bee_MVC_ModelAndView) { $this->resolveModelAndView($modelElem); - } else if(is_array($modelElem)) { + } else if (is_array($modelElem)) { $this->resolveModelInternals($modelElem); } } } - + /** * Enter description here... * - * @return _BeeHttpRequest + * @return Bee_MVC_HttpRequest */ private function buildRequestObject() { return new Bee_MVC_HttpRequest(); @@ -314,9 +342,9 @@ self::includeDispatch(Bee_MVC_HttpRequest::constructRequest(MODEL::get(MODEL::CURRENT_REQUEST_KEY), $pathInfo, $params, $method)); } - public static function subDispatchFromModel($pathInfo, array $modelKeys = null, $method=null) { + public static function subDispatchFromModel($pathInfo, array $modelKeys = null, $method = null) { $params = MODEL::getModel(); - if(is_array($modelKeys)) { + if (is_array($modelKeys)) { $params = array_intersect_key($params, array_flip($modelKeys)); } self::includeDispatch(Bee_MVC_HttpRequest::constructRequest(MODEL::get(MODEL::CURRENT_REQUEST_KEY), $pathInfo, $params, $method)); Modified: trunk/framework/Bee/MVC/HandlerExecutionChain.php =================================================================== --- trunk/framework/Bee/MVC/HandlerExecutionChain.php 2013-11-06 12:36:06 UTC (rev 121) +++ trunk/framework/Bee/MVC/HandlerExecutionChain.php 2013-11-07 17:11:37 UTC (rev 122) @@ -29,17 +29,14 @@ * @var Bee_MVC_IController */ private $handler; - - - + /** * Enter description here... * - * @var array + * @var Bee_MVC_IHandlerInterceptor[] */ private $interceptors = array(); - /** * Enter description here... * @@ -49,9 +46,7 @@ public function __construct(Bee_MVC_IController $handler) { $this->handler = $handler; } - - - + /** * Enter description here... * @@ -61,9 +56,7 @@ public function addInterceptor(Bee_MVC_IHandlerInterceptor $interceptor) { array_push($this->interceptors, $interceptor); } - - - + /** * Enter description here... * @@ -73,8 +66,7 @@ public function addInterceptors(array $interceptors) { $this->interceptors = array_merge($this->interceptors, $interceptors); } - - + /** * Enter description here... * @@ -83,9 +75,7 @@ public function getHandler() { return $this->handler; } - - - + /** * Enter description here... * Modified: trunk/framework/Bee/MVC/HandlerMapping/Abstract.php =================================================================== --- trunk/framework/Bee/MVC/HandlerMapping/Abstract.php 2013-11-06 12:36:06 UTC (rev 121) +++ trunk/framework/Bee/MVC/HandlerMapping/Abstract.php 2013-11-07 17:11:37 UTC (rev 122) @@ -40,7 +40,7 @@ /** * Enter description here... * - * @var array + * @var Bee_MVC_IHandlerInterceptor[] */ private $interceptors = array(); @@ -70,7 +70,7 @@ /** * Enter description here... * - * @param array $interceptors + * @param Bee_MVC_IHandlerInterceptor[] $interceptors */ public function setInterceptors(array $interceptors) { $this->interceptors = $interceptors; @@ -79,12 +79,17 @@ /** * Enter description here... * - * @return array + * @return Bee_MVC_IHandlerInterceptor[] */ public function getInterceptors() { return $this->interceptors; } + /** + * @param Bee_MVC_IHttpRequest $request + * @return Bee_MVC_HandlerExecutionChain + * @throws Exception + */ public function getHandler(Bee_MVC_IHttpRequest $request) { $controllerBeanName = $this->getControllerBeanName($request); $handlerBean = is_string($controllerBeanName) ? @@ -100,5 +105,10 @@ return $hec; } + /** + * Resolves the actual controller bean name (may also return a controller instance directly) + * @param Bee_MVC_IHttpRequest $request + * @return mixed + */ protected abstract function getControllerBeanName(Bee_MVC_IHttpRequest $request); } \ No newline at end of file Modified: trunk/framework/Bee/MVC/IHandlerMapping.php =================================================================== --- trunk/framework/Bee/MVC/IHandlerMapping.php 2013-11-06 12:36:06 UTC (rev 121) +++ trunk/framework/Bee/MVC/IHandlerMapping.php 2013-11-07 17:11:37 UTC (rev 122) @@ -24,20 +24,23 @@ * @author Benjamin Hartmann */ interface Bee_MVC_IHandlerMapping { - - + /** * Based on the current request object, returns a handler execution chain, containing the back controller to be used, as well as any * interceptors applicable to this request. * - * @param Bee_MVC_HttpRequest $request + * @param Bee_MVC_HttpRequest|Bee_MVC_IHttpRequest $request * @return Bee_MVC_HandlerExecutionChain - * + * * @see Bee_MVC_IController * @see Bee_MVC_IHandlerInterceptor * @see Bee_MVC_HandlerExecutionChain */ public function getHandler(Bee_MVC_IHttpRequest $request); -} -?> \ No newline at end of file + /** + * Get all configured interceptors + * @return Bee_MVC_IHandlerInterceptor[] + */ + public function getInterceptors(); +} \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |