DefaultActionMapper.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 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 
29 
30 /**
31  * Default ActionMapper implementation.
32  *
33  * @author ingo herwig <ingo@wemove.com>
34  */
36 
37  private static $logger = null;
38 
39  private $session = null;
40  private $permissionManager = null;
41  private $eventManager = null;
42  private $formatter = null;
43  private $configuration = null;
44  private $isFinished = false;
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, Response $response) {
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->setSender($referrer);
83  $response->setContext($context);
84  $response->setAction($action);
85  $response->setFormat($request->getResponseFormat());
86 
87  // check authorization for controller/context/action triple
88  if (!$this->permissionManager->authorize($referrer, $context, $action)) {
89  $authUserLogin = $this->session->getAuthUser();
90  if ($authUserLogin == AnonymousUser::USER_GROUP_NAME) {
91  self::$logger->debug("Session invalid. The request was: ".$request->__toString());
92  throw new ApplicationException($request, $response, ApplicationError::get('SESSION_INVALID'));
93  }
94  else {
95  self::$logger->debug("Authorization failed for '".$referrer.'?'.$context.'?'.$action."' user '".$authUserLogin."'");
96  throw new ApplicationException($request, $response, ApplicationError::get('PERMISSION_DENIED'));
97  }
98  }
99 
100  // get best matching action key from inifile
101  $actionKey = ActionKey::getBestMatch($actionKeyProvider, $referrer, $context, $action);
102 
103  if ($isDebugEnabled) {
104  self::$logger->debug($referrer."?".$context."?".$action.' -> '.$actionKey);
105  }
106 
107  if (strlen($actionKey) == 0) {
108  // return, if action key is not defined
109  return;
110  }
111 
112  // get next controller
113  $controllerClass = null;
114  $controllerDef = $this->configuration->getValue($actionKey, 'actionmapping');
115  if (strlen($controllerDef) == 0) {
116  self::$logger->error("No controller found for best action key ".$actionKey.
117  ". Request was $referrer?$context?$action");
118  throw new ApplicationException($request, $response, ApplicationError::get('ACTION_INVALID'));
119  }
120 
121  // check if the controller definition contains a method besides the class name
122  $controllerMethod = null;
123  if (strpos($controllerDef, '::') !== false) {
124  list($controllerClass, $controllerMethod) = explode('::', $controllerDef);
125  }
126  else {
127  $controllerClass = $controllerDef;
128  }
129 
130  // instantiate controller
131  $controllerObj = ObjectFactory::getInstanceOf($controllerClass);
132 
133  // everything is right in place, start processing
134  if ($isDebugEnabled) {
135  self::$logger->debug("Request: ".$request->__toString());
136  }
137  $this->formatter->deserialize($request);
138 
139  // initialize controller
140  if ($isDebugEnabled) {
141  self::$logger->debug("Execute ".$controllerClass." with request: ".$request->__toString());
142  }
143  $this->eventManager->dispatch(ApplicationEvent::NAME, new ApplicationEvent(
144  ApplicationEvent::BEFORE_INITIALIZE_CONTROLLER, $request, $response, $controllerObj));
145  $controllerObj->initialize($request, $response);
146 
147  // execute controller
148  $this->eventManager->dispatch(ApplicationEvent::NAME, new ApplicationEvent(
149  ApplicationEvent::BEFORE_EXECUTE_CONTROLLER, $request, $response, $controllerObj));
150  $controllerObj->execute($controllerMethod);
151  $this->eventManager->dispatch(ApplicationEvent::NAME, new ApplicationEvent(
152  ApplicationEvent::AFTER_EXECUTE_CONTROLLER, $request, $response, $controllerObj));
153 
154  // return if we are finished
155  if ($this->isFinished) {
156  $this->formatter->serialize($response);
157  return;
158  }
159 
160  // check if an action key exists for the return action
161  $nextActionKey = ActionKey::getBestMatch($actionKeyProvider, $controllerClass,
162  $response->getContext(), $response->getAction());
163  if ($isDebugEnabled) {
164  self::$logger->debug("Next action key: ".$nextActionKey);
165  }
166 
167  // terminate
168  // - if there is no next action key or
169  // - if the next action key is the same as the previous one (to prevent recursion)
170  $terminate = strlen($nextActionKey) == 0 || $actionKey == $nextActionKey;
171  if ($terminate) {
172  if ($isDebugEnabled) {
173  self::$logger->debug("Terminating with response format: ".$response->getFormat());
174  }
175  // stop processing
176  $this->formatter->serialize($response);
177  $this->isFinished = true;
178  return;
179  }
180 
181  // proceed with next action key
182  if ($isDebugEnabled) {
183  self::$logger->debug("Processing next action");
184  }
185 
186  // set the request based on the result
187  $nextRequest = ObjectFactory::getNewInstance('request');
188  $nextRequest->setSender($controllerClass);
189  $nextRequest->setContext($response->getContext());
190  $nextRequest->setAction($response->getAction());
191  $nextRequest->setFormat($response->getFormat());
192  $nextRequest->setValues($response->getValues());
193  $nextRequest->setErrors($response->getErrors());
194  $nextRequest->setResponseFormat($request->getResponseFormat());
195  $this->processAction($nextRequest, $response);
196  }
197 }
198 ?>
Session is the interface for session implementations and defines access to session variables.
Definition: Session.php:19
setSender($sender)
Set the name of the sending Controller.
Response holds the response values that are used as output from Controller instances.
Definition: Response.php:20
static getInstanceOf($class, $dynamicConfiguration=[])
Request holds the request values that are used as input to Controller instances.
Definition: Request.php:18
const AFTER_EXECUTE_CONTROLLER
A AFTER_EXECUTE_CONTROLLER event occurs after the current controller is executed.
EventManager is responsible for dispatching events to registered listeners.
getSender()
Get the name of the sending Controller.
setContext($context)
Set the name of the context.
getValues()
Get all key value pairs.
const BEFORE_ROUTE_ACTION
A BEFORE_ROUTE_ACTION event occurs before the request is mapped to an action key.
getContext()
Get the name of the context.
Default ActionMapper implementation.
getFormat()
Get the message format.
setAction($action)
Set the name of the action.
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
processAction(Request $request, Response $response)
getResponseFormat()
Get the message response format.
getAction()
Get the name of the action.
const BEFORE_INITIALIZE_CONTROLLER
A BEFORE_INITIALIZE_CONTROLLER event occurs before the current controller is initialized.
Implementations of Configuration give access to the application configuration.
Formatter is the single entry point for request/response formatting.
Definition: Formatter.php:23
ApplicationError is used to signal errors that occur while processing a request.
static get($code, $data=null)
Factory method for retrieving a predefined error instance.
ApplicationException signals a general application exception.
setFormat($format)
Set the message format.
ApplicationEvent instances are fired at different stages of the program flow.
static getLogger($name)
Get the logger with the given name.
Definition: LogManager.php:37
ConfigActionKeyProvider searches for action keys in the application configuration.
static getNewInstance($name, $dynamicConfiguration=[])
An action key is a combination of a resource, context and action that is represented as a string.
Definition: ActionKey.php:22
const BEFORE_EXECUTE_CONTROLLER
A BEFORE_EXECUTE_CONTROLLER event occurs after the current controller is initialized and before it is...
ActionMapper implementations are responsible for instantiating and executing Controllers based on the...
PermissionManager implementations are used to handle all authorization requests.
LogManager is used to retrieve Logger instances.
Definition: LogManager.php:20
ObjectFactory implements the service locator pattern by wrapping a Factory instance and providing sta...
__construct(Session $session, PermissionManager $permissionManager, EventManager $eventManager, Formatter $formatter, Configuration $configuration)
Constructor.