diff --git a/core/control/ContentController.php b/core/control/ContentController.php index 572ee9797..9357334d8 100755 --- a/core/control/ContentController.php +++ b/core/control/ContentController.php @@ -154,6 +154,14 @@ class ContentController extends Controller { return new $controllerClass($widget); } + + /** + * @uses ErrorPage::response_for() + * @return HTTPResponse + */ + public function httpError($code, $message = null) { + return ($resp = ErrorPage::response_for($code, $this->request)) ? $resp : parent::httpError($code, $message); + } /** * Get the project name diff --git a/core/control/ModelAsController.php b/core/control/ModelAsController.php index a09c9c72b..0a0b9e92d 100644 --- a/core/control/ModelAsController.php +++ b/core/control/ModelAsController.php @@ -29,6 +29,8 @@ class ModelAsController extends Controller implements NestedController { public function handleRequest($request) { $this->pushCurrent(); + + $this->request = $request; $this->urlParams = $request->allParams(); $this->init(); @@ -74,7 +76,7 @@ class ModelAsController extends Controller implements NestedController { return $response; } - $child = $this->get404Page(); + return ErrorPage::response_for(404, $this->request); } if($child) { @@ -137,15 +139,6 @@ class ModelAsController extends Controller implements NestedController { return false; } - protected function get404Page() { - $page = DataObject::get_one("ErrorPage", "\"ErrorCode\" = '404'"); - if($page) { - return $page; - } else { - // @deprecated 2.5 Use ErrorPage class - return DataObject::get_one("SiteTree", "\"URLSegment\" = '404'"); - } - } } ?> diff --git a/core/model/ErrorPage.php b/core/model/ErrorPage.php index 5e942dcf0..b507921e0 100755 --- a/core/model/ErrorPage.php +++ b/core/model/ErrorPage.php @@ -24,6 +24,46 @@ class ErrorPage extends Page { protected static $static_filepath = ASSETS_PATH; + /** + * Get a {@link HTTPResponse} that is suitable for responding to a reques that has thrown a specific error code. + * + * @param int $statusCode The HTTP error code. + * @param HTTPRequest $request The request object that triggered the error. + * @return HTTPResponse + */ + public static function response_for($statusCode, HTTPRequest $request = null) { + $errorPage = null; + + // First attempt to dynamically generate the error page, then fall back on using a cached version. + if ( + (!$request || !$request->isMedia()) && !$errorPage = DataObject::get_one('ErrorPage', "\"ErrorCode\" = $statusCode") + ) { + $cachedPath = self::get_filepath_for_errorcode($statusCode, Translatable::get_current_locale()); + + if(file_exists($cachedPath)) { + $response = new HTTPResponse(); + + $response->setStatusCode($statusCode); + $response->setBody(file_get_contents($cachedPath)); + + return $response; + } + } + + // If the request is for a simple media type, or there was no matching dynamic or cached error page just return + // a simple error string to avoid clogging up server resources. + if(!$errorPage) { + $response = new HTTPResponse(); + + $response->setStatusCode($statusCode); + $response->setBody(sprintf('Error %s: %s', $response->getStatusCode(), $response->getStatusDescription())); + + return $response; + } + + return ModelAsController::controller_for($errorPage)->handleRequest(new HTTPRequest('GET', '')); + } + /** * Ensures that there is always a 404 page * by checking if there's an instance of