[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.
|