/**
  * 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;
 }
 /**
  * (non-PHPdoc)
  * @see IActionController::executeAction()
  */
 public function executeAction($parameters)
 {
     $user = $this->_websoccer->getUser();
     $teamId = $user->getClubId($this->_websoccer, $this->_db);
     if ($teamId < 1) {
         return null;
     }
     // any number entered?
     if (!$parameters["side_standing"] && !$parameters["side_seats"] && !$parameters["grand_standing"] && !$parameters["grand_seats"] && !$parameters["vip"]) {
         return null;
     }
     $stadium = StadiumsDataService::getStadiumByTeamId($this->_websoccer, $this->_db, $teamId);
     if (!$stadium) {
         return null;
     }
     // max limit exceeded?
     $seatsSide = $stadium["places_stands"] + $stadium["places_seats"] + $parameters["side_standing"] + $parameters["side_seats"];
     if ($seatsSide > $this->_websoccer->getConfig("stadium_max_side")) {
         throw new Exception($this->_i18n->getMessage("stadium_extend_err_exceed_max_side", $this->_websoccer->getConfig("stadium_max_side")));
     }
     $seatsGrand = $stadium["places_stands_grand"] + $stadium["places_seats_grand"] + $parameters["grand_standing"] + $parameters["grand_seats"];
     if ($seatsGrand > $this->_websoccer->getConfig("stadium_max_grand")) {
         throw new Exception($this->_i18n->getMessage("stadium_extend_err_exceed_max_grand", $this->_websoccer->getConfig("stadium_max_grand")));
     }
     $seatsVip = $stadium["places_vip"] + $parameters["vip"];
     if ($seatsVip > $this->_websoccer->getConfig("stadium_max_vip")) {
         throw new Exception($this->_i18n->getMessage("stadium_extend_err_exceed_max_vip", $this->_websoccer->getConfig("stadium_max_vip")));
     }
     // is construction already on-going?
     if (StadiumsDataService::getCurrentConstructionOrderOfTeam($this->_websoccer, $this->_db, $teamId) != NULL) {
         throw new Exception($this->_i18n->getMessage("stadium_extend_err_constructionongoing"));
     }
     if (isset($parameters["validate-only"]) && $parameters["validate-only"]) {
         return "stadium-extend-confirm";
     }
     // builder got selected? Illegal builder ID can only happen due to a bug or user input manipulation.
     $builderId = $this->_websoccer->getRequestParameter("offerid");
     $offers = StadiumsDataService::getBuilderOffersForExtension($this->_websoccer, $this->_db, $teamId, (int) $this->_websoccer->getRequestParameter("side_standing"), (int) $this->_websoccer->getRequestParameter("side_seats"), (int) $this->_websoccer->getRequestParameter("grand_standing"), (int) $this->_websoccer->getRequestParameter("grand_seats"), (int) $this->_websoccer->getRequestParameter("vip"));
     if ($builderId == NULL || !isset($offers[$builderId])) {
         throw new Exception("Illegal offer ID.");
     }
     // can user afford it?
     $offer = $offers[$builderId];
     $team = TeamsDataService::getTeamSummaryById($this->_websoccer, $this->_db, $teamId);
     $totalCosts = $offer["totalCosts"];
     if ($team["team_budget"] <= $totalCosts) {
         throw new Exception($this->_i18n->getMessage("stadium_extend_err_too_expensive"));
     }
     // try to debit premium fee
     if ($offer["builder_premiumfee"]) {
         PremiumDataService::debitAmount($this->_websoccer, $this->_db, $user->id, $offer["builder_premiumfee"], "extend-stadium");
     }
     // debit money
     BankAccountDataService::debitAmount($this->_websoccer, $this->_db, $teamId, $totalCosts, "stadium_extend_transaction_subject", $offer["builder_name"]);
     // create construction order
     $this->_db->queryInsert(array("team_id" => $teamId, "builder_id" => $builderId, "started" => $this->_websoccer->getNowAsTimestamp(), "deadline" => $offer["deadline"], "p_steh" => $parameters["side_standing"] ? $parameters["side_standing"] : 0, "p_sitz" => $parameters["side_seats"] ? $parameters["side_seats"] : 0, "p_haupt_steh" => $parameters["grand_standing"] ? $parameters["grand_standing"] : 0, "p_haupt_sitz" => $parameters["grand_seats"] ? $parameters["grand_seats"] : 0, "p_vip" => $parameters["vip"] ? $parameters["vip"] : 0), $this->_websoccer->getConfig("db_prefix") . "_stadium_construction");
     // success message
     $this->_websoccer->addFrontMessage(new FrontMessage(MESSAGE_TYPE_SUCCESS, $this->_i18n->getMessage("stadium_extend_success"), ""));
     // create action log manually here, ceause of this great "validate-only" idea...
     ActionLogDataService::createOrUpdateActionLog($this->_websoccer, $this->_db, $user->id, "extend-stadium");
     $seats = $parameters["side_standing"] + $parameters["side_seats"] + $parameters["grand_standing"] + $parameters["grand_seats"] + $parameters["vip"];
     BadgesDataService::awardBadgeIfApplicable($this->_websoccer, $this->_db, $user->id, 'stadium_construction_by_x', $seats);
     return "stadium";
 }
 public function getTemplateParameters()
 {
     return array("activities" => ActionLogDataService::getLatestActionLogs($this->_websoccer, $this->_db, 5));
 }
 public function getTemplateParameters()
 {
     return array("activities" => ActionLogDataService::getActionLogsOfUser($this->_websoccer, $this->_db, $this->_websoccer->getRequestParameter('userid')));
 }