/**
  * Securely calls an action. Before the actual call, this handler will validate all parameters defined at the module.xml
  * and check the user permissions.
  * 
  * @param WebSoccer $website Current WebSoccer context.
  * @param DbConnection $db Data base connection.
  * @param I18n $i18n Messages context.
  * @param string $actionId ID of action to validate and execute.
  * @return string|NULL ID of page to display after the execution of this action or NULL if the current page shall be displayed.
  * @throws Exception if action could not be found, a double-submit occured, access is denied, controller could not be found 
  * or if the executed controller has thrown an Exception.
  */
 public static function handleAction(WebSoccer $website, DbConnection $db, I18n $i18n, $actionId)
 {
     if ($actionId == NULL) {
         return;
     }
     // check double-submit
     if (isset($_SESSION[DOUBLE_SUBMIT_CHECK_SESSIONKEY_ACTIONID]) && $_SESSION[DOUBLE_SUBMIT_CHECK_SESSIONKEY_ACTIONID] == $actionId && isset($_SESSION[DOUBLE_SUBMIT_CHECK_SESSIONKEY_TIME]) && $_SESSION[DOUBLE_SUBMIT_CHECK_SESSIONKEY_TIME] + DOUBLE_SUBMIT_CHECK_SECONDS > $website->getNowAsTimestamp()) {
         throw new Exception($i18n->getMessage('error_double_submit'));
     }
     $actionConfig = json_decode($website->getAction($actionId), true);
     $actionXml = ModuleConfigHelper::findModuleConfigAsXmlObject($actionConfig['module']);
     // check permissions
     $user = $website->getUser();
     // is admin action
     if (strpos($actionConfig['role'], 'admin') !== false) {
         if (!$user->isAdmin()) {
             throw new AccessDeniedException($i18n->getMessage('error_access_denied'));
         }
     } else {
         // all other actions
         $requiredRoles = explode(',', $actionConfig['role']);
         if (!in_array($user->getRole(), $requiredRoles)) {
             throw new AccessDeniedException($i18n->getMessage('error_access_denied'));
         }
     }
     // validate parameters
     $params = $actionXml->xpath('//action[@id = "' . $actionId . '"]/param');
     $validatedParams = array();
     if ($params) {
         $validatedParams = self::_validateParameters($params, $website, $i18n);
     }
     $controllerName = $actionConfig['controller'];
     // handle premium actions
     if (isset($actionConfig['premiumBalanceMin']) && $actionConfig['premiumBalanceMin']) {
         return self::_handlePremiumAction($website, $db, $i18n, $actionId, $actionConfig['premiumBalanceMin'], $validatedParams, $controllerName);
     }
     $actionReturn = self::_executeAction($website, $db, $i18n, $actionId, $controllerName, $validatedParams);
     // create log entry
     if (isset($actionConfig['log']) && $actionConfig['log'] && $website->getUser()->id) {
         ActionLogDataService::createOrUpdateActionLog($website, $db, $website->getUser()->id, $actionId);
     }
     return $actionReturn;
 }