DefaultActionMapper.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2015 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
12 
28 
29 /**
30  * Default ActionMapper implementation.
31  *
32  * @author ingo herwig <ingo@wemove.com>
33  */
35 
36  private static $_logger = null;
37 
38  private $_lastResponses = array();
39  private $_session = null;
40  private $_permissionManager = null;
41  private $_eventManager = null;
42  private $_formatter = null;
43  private $_configuration = null;
44 
45 
46  /**
47  * Constructor
48  * @param $session
49  * @param $permissionManager
50  * @param $eventManager
51  * @param $formatter
52  * @param $configuration
53  */
54  public function __construct(Session $session,
55  PermissionManager $permissionManager,
56  EventManager $eventManager,
57  Formatter $formatter,
58  Configuration $configuration) {
59  if (self::$_logger == null) {
60  self::$_logger = LogManager::getLogger(__CLASS__);
61  }
62  $this->_session = $session;
63  $this->_permissionManager = $permissionManager;
64  $this->_eventManager = $eventManager;
65  $this->_formatter = $formatter;
66  $this->_configuration = $configuration;
67  }
68 
69  /**
70  * @see ActionMapper::processAction()
71  */
72  public function processAction(Request $request) {
73  $isDebugEnabled = self::$_logger->isDebugEnabled();
74 
75  $this->_eventManager->dispatch(ApplicationEvent::NAME, new ApplicationEvent(
77  $actionKeyProvider = new ConfigActionKeyProvider($this->_configuration, 'actionmapping');
78 
79  $referrer = $request->getSender();
80  $context = $request->getContext();
81  $action = $request->getAction();
82  $response = ObjectFactory::getInstance('response');
83  $response->setSender($referrer);
84  $response->setContext($context);
85  $response->setFormat($request->getResponseFormat());
86 
87  // check authorization for controller/context/action triple
88  if (!$this->_permissionManager->authorize($referrer, $context, $action)) {
89  $authUser = $this->_session->getAuthUser();
90  if ($authUser instanceof AnonymousUser) {
91  self::$_logger->error("Session invalid. The request was: ".$request->__toString());
92  throw new ApplicationException($request, $response, ApplicationError::get('SESSION_INVALID'));
93  }
94  else {
95  $login = $authUser->getLogin();
96  self::$_logger->error("Authorization failed for '".$referrer.'?'.$context.'?'.$action."' user '".$login."'");
97  throw new ApplicationException($request, $response, ApplicationError::get('PERMISSION_DENIED'));
98  }
99  }
100 
101  // get best matching action key from inifile
102  $actionKey = ActionKey::getBestMatch($actionKeyProvider, $referrer, $context, $action);
103 
104  if ($isDebugEnabled) {
105  self::$_logger->debug($referrer."?".$context."?".$action.' -> '.$actionKey);
106  }
107 
108  $controllerClass = null;
109  if (strlen($actionKey) == 0) {
110  // return last response, if action key is not defined
111  $lastResponse = array_pop($this->_lastResponses);
112  return $lastResponse;
113  }
114  else {
115  // get next controller
116  $controllerDef = $this->_configuration->getValue($actionKey, 'actionmapping');
117  }
118  if (strlen($controllerDef) == 0) {
119  throw new ApplicationException($request, $response, "No controller found for best action key ".$actionKey.". Request was $referrer?$context?$action");
120  }
121 
122  // check if the controller definition contains a method besides the class name
123  $controllerMethod = null;
124  if (strpos($controllerDef, '::') !== false) {
125  list($controllerClass, $controllerMethod) = explode('::', $controllerDef);
126  }
127  else {
128  $controllerClass = $controllerDef;
129  }
130 
131  // instantiate controller
132  $controllerObj = ObjectFactory::getClassInstance($controllerClass);
133 
134  // everything is right in place, start processing
135  if ($isDebugEnabled) {
136  self::$_logger->debug("Request: ".$request->__toString());
137  }
138  $this->_formatter->deserialize($request);
139 
140  // initialize controller
141  if ($isDebugEnabled) {
142  self::$_logger->debug("Execute ".$controllerClass." with request: ".$request->__toString());
143  }
144  $this->_eventManager->dispatch(ApplicationEvent::NAME, new ApplicationEvent(
145  ApplicationEvent::BEFORE_INITIALIZE_CONTROLLER, $request, $response, $controllerObj));
146  $controllerObj->initialize($request, $response);
147 
148  // execute controller
149  $this->_eventManager->dispatch(ApplicationEvent::NAME, new ApplicationEvent(
150  ApplicationEvent::BEFORE_EXECUTE_CONTROLLER, $request, $response, $controllerObj));
151  $controllerObj->execute($controllerMethod);
152  $this->_eventManager->dispatch(ApplicationEvent::NAME, new ApplicationEvent(
153  ApplicationEvent::AFTER_EXECUTE_CONTROLLER, $request, $response, $controllerObj));
154 
155  // check if an action key exists for the return action
156  $nextActionKey = ActionKey::getBestMatch($actionKeyProvider, $controllerClass,
157  $response->getContext(), $response->getAction());
158  if ($isDebugEnabled) {
159  self::$_logger->debug("Next action key: ".$nextActionKey);
160  }
161 
162  // terminate, if there is no next action key or the response is final
163  $terminate = strlen($nextActionKey) == 0 || $response->isFinal();
164  if ($terminate) {
165  if ($isDebugEnabled) {
166  self::$_logger->debug("Terminate");
167  }
168  // stop processing
169  $this->_formatter->serialize($response);
170  return $response;
171  }
172 
173  // proceed with next action key
174  if ($isDebugEnabled) {
175  self::$_logger->debug("Processing next action");
176  }
177  // store last response
178  $this->_lastResponses[] = $response;
179 
180  // set the request based on the result
181  $nextRequest = ObjectFactory::getInstance('request');
182  $nextRequest->setSender($controllerClass);
183  $nextRequest->setContext($response->getContext());
184  $nextRequest->setAction($response->getAction());
185  $nextRequest->setFormat($response->getFormat());
186  $nextRequest->setValues($response->getValues());
187  $nextRequest->setErrors($response->getErrors());
188  $nextRequest->setResponseFormat($request->getResponseFormat());
189  $this->processAction($nextRequest);
190  }
191 
192  /**
193  * @see ActionMapper::reset()
194  */
195  public function reset() {
196  $this->_lastResponses = array();
197  }
198 }
199 ?>
static getClassInstance($class, $dynamicConfiguration=array())
static getBestMatch(ActionKeyProvider $actionKeyProvider, $resource, $context, $action)
Get an action key that matches a given combination of resource, context, action best.
Definition: ActionKey.php:55
Default ActionMapper implementation.
EventManager is responsible for dispatching events to registered listeners.
const BEFORE_INITIALIZE_CONTROLLER
A BEFORE_INITIALIZE_CONTROLLER event occurs before the current controller is initialized.
getContext()
Get the name of the context.
static getLogger($name)
Get the logger with the given name.
Definition: LogManager.php:35
const AFTER_EXECUTE_CONTROLLER
A AFTER_EXECUTE_CONTROLLER event occurs after the current controller is executed. ...
static getInstance($name, $dynamicConfiguration=array())
getResponseFormat()
Get the message response format.
Formatter is the single entry point for request/response formatting.
Definition: Formatter.php:23
getAction()
Get the name of the action.
Session is the interface for session implementations and defines access to session variables...
Definition: Session.php:21
Request holds the request values that are used as input to Controller instances.
Definition: Request.php:20
const BEFORE_EXECUTE_CONTROLLER
A BEFORE_EXECUTE_CONTROLLER event occurs after the current controller is initialized and before it is...
getSender()
Get the name of the sending Controller.
const BEFORE_ROUTE_ACTION
A BEFORE_ROUTE_ACTION event occurs before the request is mapped to an action key. ...
ApplicationEvent instances are fired at different stages of the program flow.
ConfigActionKeyProvider searches for action keys in the application configuration.
PermissionManager implementations are used to handle all authorization requests.
Implementations of Configuration give access to the application configuration.
ActionMapper implementations are responsible for instantiating and executing Controllers based on the...
static get($code, $data=null)
Factory method for retrieving a predefind error instance.
ApplicationException signals a general application exception.
__construct(Session $session, PermissionManager $permissionManager, EventManager $eventManager, Formatter $formatter, Configuration $configuration)
Constructor.