function run($requestParams) { if (isset($_GET['debug_profile'])) { Profiler::mark("Controller", "run"); } $this->pushCurrent(); $this->response = new HTTPResponse(); $this->requestParams = $requestParams; $this->action = isset($this->urlParams['Action']) ? str_replace("-", "_", $this->urlParams['Action']) : ""; if (!$this->action) { $this->action = 'index'; } // Check security on the controller if (!$this->checkAccessAction($this->action)) { user_error("Disallowed action: '{$this->action}' on controller '{$this->class}'", E_USER_ERROR); } // Init $this->baseInitCalled = false; $this->init(); if (!$this->baseInitCalled) { user_error("init() method on class '{$this->class}' doesn't call Controller::init(). Make sure that you have parent::init() included.", E_USER_WARNING); } // If we had a redirection or something, halt processing. if ($this->response->isFinished()) { $this->popCurrent(); return $this->response; } // Look at the action variables for forms $funcName = null; foreach ($this->requestParams as $paramName => $paramVal) { if (substr($paramName, 0, 7) == 'action_') { // Cleanup action_, _x and _y from image fields $funcName = preg_replace(array('/^action_/', '/_x$|_y$/'), '', $paramName); break; } } // Form handler if (isset($this->requestParams['executeForm']) && is_string($this->requestParams['executeForm'])) { if (isset($funcName)) { Form::set_current_action($funcName); } // Get the appropraite ocntroller: sometimes we want to get a form from another controller if (isset($this->requestParams['formController'])) { $formController = Director::getControllerForURL($this->requestParams['formController']); while (is_a($formController, 'NestedController')) { $formController = $formController->getNestedController(); } } else { $formController = $this; } // Create the form object $form = $formController; $formObjParts = explode('.', $this->requestParams['executeForm']); foreach ($formObjParts as $formMethod) { if (isset($_GET['debug_profile'])) { Profiler::mark("Calling {$formMethod}", "on {$form->class}"); } $form = $form->{$formMethod}(); if (isset($_GET['debug_profile'])) { Profiler::unmark("Calling {$formMethod}", "on {$form->class}"); } if (!$form) { break; } //user_error("Form method '" . $this->requestParams['executeForm'] . "' returns null in controller class '$this->class' ($_SERVER[REQUEST_URI])", E_USER_ERROR); } // Populate the form if (isset($_GET['debug_profile'])) { Profiler::mark("Controller", "populate form"); } if ($form) { $form->loadDataFrom($this->requestParams, true); // disregard validation if a single field is called if (!isset($_REQUEST['action_callfieldmethod'])) { $valid = $form->beforeProcessing(); if (!$valid) { $this->popCurrent(); return $this->response; } } else { $fieldcaller = $form->dataFieldByName($requestParams['fieldName']); if (is_a($fieldcaller, "TableListField")) { if ($fieldcaller->hasMethod('php')) { $valid = $fieldcaller->php($requestParams); if (!$valid) { exit; } } } } // If the action wasnt' set, choose the default on the form. if (!isset($funcName) && ($defaultAction = $form->defaultAction())) { $funcName = $defaultAction->actionName(); } if (isset($funcName)) { $form->setButtonClicked($funcName); } } else { user_error("No form (" . Session::get('CMSMain.currentPage') . ") returned by {$formController->class}->{$_REQUEST['executeForm']}", E_USER_WARNING); } if (isset($_GET['debug_profile'])) { Profiler::unmark("Controller", "populate form"); } if (!isset($funcName)) { user_error("No action button has been clicked in this form executon, and no default has been allowed", E_USER_ERROR); } // Protection against CSRF attacks if ($form->securityTokenEnabled()) { $securityID = Session::get('SecurityID'); if (!$securityID || !isset($this->requestParams['SecurityID']) || $securityID != $this->requestParams['SecurityID']) { // Don't show error on live sites, as spammers create a million of these if (!Director::isLive()) { trigger_error("Security ID doesn't match, possible CRSF attack.", E_USER_ERROR); } else { die; } } } // First, try a handler method on the controller if ($this->hasMethod($funcName) || !$form) { if (isset($_GET['debug_controller'])) { Debug::show("Found function {$funcName} on the controller"); } if (isset($_GET['debug_profile'])) { Profiler::mark("{$this->class}::{$funcName} (controller action)"); } $result = $this->{$funcName}($this->requestParams, $form); if (isset($_GET['debug_profile'])) { Profiler::unmark("{$this->class}::{$funcName} (controller action)"); } // Otherwise, try a handler method on the form object } else { if (isset($_GET['debug_controller'])) { Debug::show("Found function {$funcName} on the form object"); } if (isset($_GET['debug_profile'])) { Profiler::mark("{$form->class}::{$funcName} (form action)"); } $result = $form->{$funcName}($this->requestParams, $form); if (isset($_GET['debug_profile'])) { Profiler::unmark("{$form->class}::{$funcName} (form action)"); } } // Normal action } else { if (!isset($funcName)) { $funcName = $this->action; } if ($this->hasMethod($funcName)) { if (isset($_GET['debug_controller'])) { Debug::show("Found function {$funcName} on the {$this->class} controller"); } if (isset($_GET['debug_profile'])) { Profiler::mark("{$this->class}::{$funcName} (controller action)"); } $result = $this->{$funcName}($this->urlParams); if (isset($_GET['debug_profile'])) { Profiler::unmark("{$this->class}::{$funcName} (controller action)"); } } else { if (isset($_GET['debug_controller'])) { Debug::show("Running default action for {$funcName} on the {$this->class} controller"); } if (isset($_GET['debug_profile'])) { Profiler::mark("Controller::defaultAction({$funcName})"); } $result = $this->defaultAction($funcName, $this->urlParams); if (isset($_GET['debug_profile'])) { Profiler::unmark("Controller::defaultAction({$funcName})"); } } } // If your controller function returns an array, then add that data to the // default template if (is_array($result)) { $extended = $this->customise($result); $viewer = $this->getViewer($funcName); $result = $viewer->process($extended); } $this->response->setBody($result); if ($result) { ContentNegotiator::process($this->response); } // Set up HTTP cache headers HTTP::add_cache_headers($this->response); if (isset($_GET['debug_profile'])) { Profiler::unmark("Controller", "run"); } $this->popCurrent(); return $this->response; }
/** * Return the object that is going to own a form that's being processed, and handle its execution. * Note that the result needn't be an actual controller object. */ function getFormOwner() { // Get the appropraite ocntroller: sometimes we want to get a form from another controller if(isset($this->requestParams['formController'])) { $formController = Director::getControllerForURL($this->requestParams['formController']); while(is_a($formController, 'NestedController')) { $formController = $formController->getNestedController(); } return $formController; } else { return $this; } }
/** * Test a URL request, returning a response object. * * This method is the counterpart of Director::direct() that is used in functional testing. It will execute the URL given, * * @param $url The URL to visit * @param $post The $_POST & $_FILES variables * @param $session The {@link Session} object representing the current session. By passing the same object to multiple * calls of Director::test(), you can simulate a peristed session. * * @uses getControllerForURL() The rule-lookup logic is handled by this. * @uses Controller::run() Controller::run() handles the page logic for a Director::direct() call. */ function test($url, $post = null, $session = null) { $getVars = array(); if (strpos($url, '?') !== false) { list($url, $getVarsEncoded) = explode('?', $url, 2); parse_str($getVarsEncoded, $getVars); } $controllerObj = Director::getControllerForURL($url); // Load the session into the controller $controllerObj->setSession($session ? $session : new Session(null)); if (is_string($controllerObj) && substr($controllerObj, 0, 9) == 'redirect:') { user_error("Redirection not implemented in Director::test", E_USER_ERROR); } else { if ($controllerObj) { $response = $controllerObj->run(array_merge($getVars, (array) $post)); return $response; } } }