/** * Returns the appropriate response up the controller chain * if {@link validate()} fails (which is checked prior to executing any form actions). * By default, returns different views for ajax/non-ajax request, and * handles 'application/json' requests with a JSON object containing the error messages. * Behaviour can be influenced by setting {@link $redirectToFormOnValidationError}, * and can be overruled by setting {@link $validationResponseCallback}. * * @return HTTPResponse|string */ protected function getValidationErrorResponse() { $callback = $this->getValidationResponseCallback(); if ($callback && ($callbackResponse = $callback())) { return $callbackResponse; } $request = $this->getRequest(); if ($request->isAjax()) { // Special case for legacy Validator.js implementation // (assumes eval'ed javascript collected through FormResponse) $acceptType = $request->getHeader('Accept'); if (strpos($acceptType, 'application/json') !== FALSE) { // Send validation errors back as JSON with a flag at the start $response = new HTTPResponse(Convert::array2json($this->validator->getErrors())); $response->addHeader('Content-Type', 'application/json'); } else { $this->setupFormErrors(); // Send the newly rendered form tag as HTML $response = new HTTPResponse($this->forTemplate()); $response->addHeader('Content-Type', 'text/html'); } return $response; } else { if ($this->getRedirectToFormOnValidationError()) { if ($pageURL = $request->getHeader('Referer')) { if (Director::is_site_url($pageURL)) { // Remove existing pragmas $pageURL = preg_replace('/(#.*)/', '', $pageURL); $pageURL = Director::absoluteURL($pageURL, true); return $this->controller->redirect($pageURL . '#' . $this->FormName()); } } } return $this->controller->redirectBack(); } }
/** * Overloaded redirection logic to trigger a fake redirect on ajax requests. * While this violates HTTP principles, its the only way to work around the * fact that browsers handle HTTP redirects opaquely, no intervention via JS is possible. * In isolation, that's not a problem - but combined with history.pushState() * it means we would request the same redirection URL twice if we want to update the URL as well. * See LeftAndMain.js for the required jQuery ajaxComplete handlers. * * @param string $url * @param int $code * @return HTTPResponse|string */ public function redirect($url, $code = 302) { if ($this->getRequest()->isAjax()) { $response = $this->getResponse(); $response->addHeader('X-ControllerURL', $url); if ($this->getRequest()->getHeader('X-Pjax') && !$response->getHeader('X-Pjax')) { $response->addHeader('X-Pjax', $this->getRequest()->getHeader('X-Pjax')); } $newResponse = new LeftAndMain_HTTPResponse($response->getBody(), $response->getStatusCode(), $response->getStatusDescription()); foreach ($response->getHeaders() as $k => $v) { $newResponse->addHeader($k, $v); } $newResponse->setIsFinished(true); $this->setResponse($newResponse); return ''; // Actual response will be re-requested by client } else { parent::redirect($url, $code); } }