/** * Ensures that there is always a 404 page by checking if there's an * instance of ErrorPage with a 404 and 500 error code. If there is not, * one is created when the DB is built. */ public function requireDefaultRecords() { parent::requireDefaultRecords(); if ($this->class === 'ErrorPage' && SiteTree::config()->create_default_pages) { $defaultPages = $this->getDefaultRecords(); foreach ($defaultPages as $defaultData) { $code = $defaultData['ErrorCode']; $page = ErrorPage::get()->filter('ErrorCode', $code)->first(); $pageExists = !empty($page); if (!$pageExists) { $page = new ErrorPage($defaultData); $page->write(); $page->publish('Stage', 'Live'); } // Check if static files are enabled if (!self::config()->enable_static_file) { continue; } // Ensure this page has cached error content $success = true; if (!$page->hasStaticPage()) { // Update static content $success = $page->writeStaticPage(); } elseif ($pageExists) { // If page exists and already has content, no alteration_message is displayed continue; } if ($success) { DB::alteration_message(sprintf('%s error page created', $code), 'created'); } else { DB::alteration_message(sprintf('%s error page could not be created. Please check permissions', $code), 'error'); } } } }
/** * New tests require nested urls to be enabled, but the site might not * support nested URLs. * This setup will enable nested-urls for this test and resets the state * after the tests have been performed. */ public function tearDown() { if (isset($this->orig['nested_urls']) && !$this->orig['nested_urls']) { SiteTree::config()->nested_urls = false; } parent::tearDown(); }
/** * Updates the CMS fields adding the fields defined in this extension * @param {FieldList} $fields Field List that new fields will be added to */ public function updateCMSFields(FieldList $fields) { $urlSegmentField = $fields->dataFieldByName('URLSegment'); if ($urlSegmentField) { $baseLink = Controller::join_links(Director::absoluteBaseURL(), (Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL') ? $this->owner->Locale : i18n::get_lang_from_locale($this->owner->Locale)) . '/', SiteTree::config()->nested_urls && $this->owner->ParentID ? $this->owner->Parent()->RelativeLink(true) : null); $urlSegmentField->setURLPrefix($baseLink); } }
public function testGetHomepageLink() { $default = $this->objFromFixture('Page', 'home'); SiteTree::config()->nested_urls = false; $this->assertEquals('home', RootURLController::get_homepage_link()); Config::inst()->update('SiteTree', 'nested_urls', true); $this->assertEquals('home', RootURLController::get_homepage_link()); }
public function updateCMSFields(FieldList $fields) { parent::updateCMSFields($fields); // Fix URLSegment field issue for root pages if (!SiteTree::config()->nested_urls || empty($this->owner->ParentID)) { $baseLink = Director::absoluteURL(Controller::join_links(Director::baseURL(), Fluent::alias(Fluent::current_locale()), '/')); $urlsegment = $fields->dataFieldByName('URLSegment'); $urlsegment->setURLPrefix($baseLink); } }
public function testDeepNestedURLs() { Config::inst()->update('SiteTree', 'nested_urls', true); $page = new Page(); $page->URLSegment = 'base-page'; $page->write(); for ($i = 0; $i < 10; $i++) { $parentID = $page->ID; $page = new ContentControllerTest_Page(); $page->ParentID = $parentID; $page->Title = "Page Level {$i}"; $page->URLSegment = "level-{$i}"; $page->write(); $relativeLink = Director::makeRelative($page->Link()); $this->assertEquals($page->Title, $this->get($relativeLink)->getBody()); } SiteTree::config()->nested_urls = false; }
/** * Ensures that there is always a 404 page by checking if there's an * instance of ErrorPage with a 404 and 500 error code. If there is not, * one is created when the DB is built. */ public function requireDefaultRecords() { parent::requireDefaultRecords(); if ($this->class == 'ErrorPage' && SiteTree::config()->create_default_pages) { // Ensure that an assets path exists before we do any error page creation if (!file_exists(ASSETS_PATH)) { mkdir(ASSETS_PATH); } $defaultPages = $this->getDefaultRecords(); foreach ($defaultPages as $defaultData) { $code = $defaultData['ErrorCode']; $page = DataObject::get_one('ErrorPage', sprintf("\"ErrorPage\".\"ErrorCode\" = '%s'", $code)); $pageExists = $page && $page->exists(); $pagePath = self::get_filepath_for_errorcode($code); if (!($pageExists && file_exists($pagePath))) { if (!$pageExists) { $page = new ErrorPage($defaultData); $page->write(); $page->publish('Stage', 'Live'); } // Ensure a static error page is created from latest error page content $response = Director::test(Director::makeRelative($page->Link())); $written = null; if ($fh = fopen($pagePath, 'w')) { $written = fwrite($fh, $response->getBody()); fclose($fh); } if ($written) { DB::alteration_message(sprintf('%s error page created', $code), 'created'); } else { DB::alteration_message(sprintf('%s error page could not be created at %s. Please check permissions', $code, $pagePath), 'error'); } } } } }
/** * @return ContentController * @throws Exception If URLSegment not passed in as a request parameter. */ public function getNestedController() { $request = $this->getRequest(); if (!($URLSegment = $request->param('URLSegment'))) { throw new Exception('ModelAsController->getNestedController(): was not passed a URLSegment value.'); } // Find page by link, regardless of current locale settings if (class_exists('Translatable')) { Translatable::disable_locale_filter(); } // Select child page $conditions = array('"SiteTree"."URLSegment"' => rawurlencode($URLSegment)); if (SiteTree::config()->nested_urls) { $conditions[] = array('"SiteTree"."ParentID"' => 0); } $sitetree = DataObject::get_one('SiteTree', $conditions); // Check translation module // @todo Refactor out module specific code if (class_exists('Translatable')) { Translatable::enable_locale_filter(); } if (!$sitetree) { $response = ErrorPage::response_for(404); $this->httpError(404, $response ? $response : 'The requested page could not be found.'); } // Enforce current locale setting to the loaded SiteTree object if (class_exists('Translatable') && $sitetree->Locale) { Translatable::set_current_locale($sitetree->Locale); } if (isset($_REQUEST['debug'])) { Debug::message("Using record #{$sitetree->ID} of type {$sitetree->class} with link {$sitetree->Link()}"); } return self::controller_for($sitetree, $this->getRequest()->param('Action')); }
/** * @covers SiteTree::validURLSegment */ public function testValidURLSegmentURLSegmentConflicts() { $sitetree = new SiteTree(); SiteTree::config()->nested_urls = false; $sitetree->URLSegment = 'home'; $this->assertFalse($sitetree->validURLSegment(), 'URLSegment conflicts are recognised'); $sitetree->URLSegment = 'home-noconflict'; $this->assertTrue($sitetree->validURLSegment()); $sitetree->ParentID = $this->idFromFixture('Page', 'about'); $sitetree->URLSegment = 'home'; $this->assertFalse($sitetree->validURLSegment(), 'Conflicts are still recognised with a ParentID value'); Config::inst()->update('SiteTree', 'nested_urls', true); $sitetree->ParentID = 0; $sitetree->URLSegment = 'home'; $this->assertFalse($sitetree->validURLSegment(), 'URLSegment conflicts are recognised'); $sitetree->ParentID = $this->idFromFixture('Page', 'about'); $this->assertTrue($sitetree->validURLSegment(), 'URLSegments can be the same across levels'); $sitetree->URLSegment = 'my-staff'; $this->assertFalse($sitetree->validURLSegment(), 'Nested URLSegment conflicts are recognised'); $sitetree->URLSegment = 'my-staff-noconflict'; $this->assertTrue($sitetree->validURLSegment()); }
public function onBeforeDelete() { parent::onBeforeDelete(); // If deleting this page, delete all its children. if (SiteTree::config()->enforce_strict_hierarchy && ($children = $this->AllChildren())) { foreach ($children as $child) { $child->delete(); } } }
/** * @return ContentController */ public function getNestedController() { $request = $this->request; if (!($URLSegment = $request->param('URLSegment'))) { throw new Exception('ModelAsController->getNestedController(): was not passed a URLSegment value.'); } // Find page by link, regardless of current locale settings if (class_exists('Translatable')) { Translatable::disable_locale_filter(); } $sitetree = DataObject::get_one('SiteTree', sprintf('"SiteTree"."URLSegment" = \'%s\' %s', Convert::raw2sql(rawurlencode($URLSegment)), SiteTree::config()->nested_urls ? 'AND "SiteTree"."ParentID" = 0' : null)); if (class_exists('Translatable')) { Translatable::enable_locale_filter(); } if (!$sitetree) { $response = ErrorPage::response_for(404); $this->httpError(404, $response ? $response : 'The requested page could not be found.'); } // Enforce current locale setting to the loaded SiteTree object if (class_exists('Translatable') && $sitetree->Locale) { Translatable::set_current_locale($sitetree->Locale); } if (isset($_REQUEST['debug'])) { Debug::message("Using record #{$sitetree->ID} of type {$sitetree->class} with link {$sitetree->Link()}"); } return self::controller_for($sitetree, $this->request->param('Action')); }
/** * This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to * fall over to a child controller in order to provide functionality for nested URLs. * * @param SS_HTTPRequest $request * @param DataModel $model * @return SS_HTTPResponse * @throws SS_HTTPResponse_Exception */ public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) { $child = null; $action = $request->param('Action'); $this->setDataModel($model); // If nested URLs are enabled, and there is no action handler for the current request then attempt to pass // control to a child controller. This allows for the creation of chains of controllers which correspond to a // nested URL. if ($action && SiteTree::config()->nested_urls && !$this->hasAction($action)) { // See ModelAdController->getNestedController() for similar logic if (class_exists('Translatable')) { Translatable::disable_locale_filter(); } // look for a page with this URLSegment $child = $this->model->SiteTree->filter(array('ParentID' => $this->ID, 'URLSegment' => rawurlencode($action)))->first(); if (class_exists('Translatable')) { Translatable::enable_locale_filter(); } } // we found a page with this URLSegment. if ($child) { $request->shiftAllParams(); $request->shift(); $response = ModelAsController::controller_for($child)->handleRequest($request, $model); } else { // If a specific locale is requested, and it doesn't match the page found by URLSegment, // look for a translation and redirect (see #5001). Only happens on the last child in // a potentially nested URL chain. if (class_exists('Translatable')) { if ($request->getVar('locale') && $this->dataRecord && $this->dataRecord->Locale != $request->getVar('locale')) { $translation = $this->dataRecord->getTranslation($request->getVar('locale')); if ($translation) { $response = new SS_HTTPResponse(); $response->redirect($translation->Link(), 301); throw new SS_HTTPResponse_Exception($response); } } } Director::set_current_page($this->data()); try { $response = parent::handleRequest($request, $model); Director::set_current_page(null); } catch (SS_HTTPResponse_Exception $e) { $this->popCurrent(); Director::set_current_page(null); throw $e; } } return $response; }
/** * Try to determine the controller for the current request. * * @return type Controller */ public function getNestedController() { $URLSegment = $this->request->param('URLSegment'); if (empty($URLSegment)) { PrefixRootURLController::set_is_at_root(); // get the homepage from the defaul homepage Translation Group $URLSegment = LanguagePrefix::get_homepage_link_by_locale($this->locale); // if no homepage is found in the default translation group for this locale // use the first page in the tree instead if (empty($URLSegment)) { //@TODO: make 3.0 $sitetree = SiteTree::get()->filter(array('ParentID' => '0', 'Locale' => $this->locale))->sort('Sort')->First(); if ($sitetree) { $URLSegment = $sitetree->URLSegment; } else { // last resort $URLSegment = self::$default_homepage_link; } } } // We have an URLSegment: find the page with this segment - within the current locale // In the original ModelAsController the locale filter is disabled for this query, // meaning /nl/englishHomePage/ will be found and be redirected later on // to /en/englishHomePage/ where I'd rather have a 404!! Translatable::enable_locale_filter(); // make sure multibyte urls are supported $sitetree = DataObject::get_one('SiteTree', sprintf('"SiteTree"."URLSegment" = \'%s\' %s', Convert::raw2sql(rawurlencode($URLSegment)), SiteTree::config()->nested_urls ? 'AND "SiteTree"."ParentID" = 0' : null)); // As in the original ModelAsController: if no page can be found, check if it // has been renamed or relocated - again: within the current locale!!! // If the current $URLSegment refers to an 'old page', do a 302 redirect to the // current version (this works for bookmarked pages) // Note: for this the find_old_page() function needs to be localized as well to // find_old_page_localized() if (empty($sitetree)) { if ($redirect = self::find_old_page_localized($URLSegment)) { $params = $this->request->getVars(); if (isset($params['url'])) { unset($params['url']); } $this->response = new SS_HTTPResponse(); $this->response->redirect(Controller::join_links($redirect->Link(Controller::join_links($this->request->param('Action'), $this->request->param('ID'), $this->request->param('OtherID'))), $params ? '?' . http_build_query($params) : null), 301); return $this->response; } // all is now lost! return $this->showPageNotFound(); } // This we don't really need anymore... // Enforce current locale setting to the loaded SiteTree object // if($sitetree->Locale) Translatable::set_current_locale($sitetree->Locale); if (isset($_REQUEST['debug'])) { Debug::message("Using record #{$sitetree->ID} of type {$sitetree->class} with link {$sitetree->Link()}"); } return self::controller_for($sitetree, $this->request->param('Action')); }