diff --git a/core/model/SiteTree.php b/core/model/SiteTree.php
index 70450a6f0..725318c15 100755
--- a/core/model/SiteTree.php
+++ b/core/model/SiteTree.php
@@ -227,6 +227,72 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
self::$nested_urls = false;
}
+ /**
+ * Fetches the {@link SiteTree} object that maps to a link.
+ *
+ * If you have enabled {@link SiteTree::nested_urls()} on this site, then you can use a nested link such as
+ * "about-us/staff/", and this function will traverse down the URL chain and grab the appropriate link.
+ *
+ * Note that if no model can be found, this method will fall over to a decorated alternateGetByLink method provided
+ * by a decorator attached to {@link SiteTree}
+ *
+ * @param string $link
+ * @param bool $cache
+ * @return SiteTree
+ */
+ public static function get_by_link($link, $cache = true) {
+ if(trim($link, '/')) {
+ $link = trim(Director::makeRelative($link), '/');
+ } else {
+ $link = RootURLController::get_homepage_urlsegment();
+ }
+
+ $parts = Convert::raw2sql(preg_split('|/+|', $link));
+
+ // Grab the initial root level page to traverse down from.
+ $URLSegment = array_shift($parts);
+ $sitetree = DataObject::get_one (
+ 'SiteTree', "\"URLSegment\" = '$URLSegment'" . (self::nested_urls() ? ' AND "ParentID" = 0' : ''), $cache
+ );
+
+ /// Fall back on a unique URLSegment for b/c.
+ if(!$sitetree && self::nested_urls() && $pages = DataObject::get('SiteTree', "\"URLSegment\" = '$URLSegment'")) {
+ return ($pages->Count() == 1) ? $pages->First() : null;
+ }
+
+ // Attempt to grab an alternative page from decorators.
+ if(!$sitetree) {
+ if($alternatives = singleton('SiteTree')->extend('alternateGetByLink', $link, $filter, $cache, $order)) {
+ foreach($alternatives as $alternative) if($alternative) return $alternative;
+ }
+
+ return false;
+ }
+
+ // Check if we have any more URL parts to parse.
+ if(!self::nested_urls() || !count($parts)) return $sitetree;
+
+ // Traverse down the remaining URL segments and grab the relevant SiteTree objects.
+ foreach($parts as $segment) {
+ $next = DataObject::get_one (
+ 'SiteTree', "\"URLSegment\" = '$segment' AND \"ParentID\" = $sitetree->ID", $cache
+ );
+
+ if(!$next) {
+ if($alternatives = singleton('SiteTree')->extend('alternateGetByLink', $link, $filter, $cache, $order)) {
+ foreach($alternatives as $alternative) if($alternative) return $alternative;
+ }
+
+ return false;
+ }
+
+ $sitetree->destroy();
+ $sitetree = $next;
+ }
+
+ return $sitetree;
+ }
+
/**
* Return a subclass map of SiteTree
* that shouldn't be hidden through
@@ -263,26 +329,26 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return $classes;
}
- /**
- * Replace a "[sitetree_link id=n]" shortcode with a link to the page with the corresponding ID.
- *
- * @return string
- */
- public static function link_shortcode_handler($arguments, $content = null, $parser = null) {
- if(!isset($arguments['id']) || !is_numeric($arguments['id'])) return;
-
- if (
- !($page = DataObject::get_by_id('SiteTree', $arguments['id'])) // Get the current page by ID.
- && !($page = Versioned::get_latest_version('SiteTree', $arguments['id'])) // Attempt link to old version.
- && !($page = DataObject::get_one('ErrorPage', '"ErrorCode" = \'404\'')) // Link to 404 page directly.
- ) {
- return; // There were no suitable matches at all.
- }
-
- if($content) {
- return sprintf('%s', $page->Link(), $parser->parse($content));
- } else {
- return $page->Link();
+ /**
+ * Replace a "[sitetree_link id=n]" shortcode with a link to the page with the corresponding ID.
+ *
+ * @return string
+ */
+ public static function link_shortcode_handler($arguments, $content = null, $parser = null) {
+ if(!isset($arguments['id']) || !is_numeric($arguments['id'])) return;
+
+ if (
+ !($page = DataObject::get_by_id('SiteTree', $arguments['id'])) // Get the current page by ID.
+ && !($page = Versioned::get_latest_version('SiteTree', $arguments['id'])) // Attempt link to old version.
+ && !($page = DataObject::get_one('ErrorPage', '"ErrorCode" = \'404\'')) // Link to 404 page directly.
+ ) {
+ return; // There were no suitable matches at all.
+ }
+
+ if($content) {
+ return sprintf('%s', $page->Link(), $parser->parse($content));
+ } else {
+ return $page->Link();
}
}
@@ -1365,27 +1431,14 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
}
/**
- * Return the SiteTree object with the given URL segment.
- *
- * @param string $urlSegment The URL segment, eg 'home'
- * @param string $extraFilter
- * @param boolean $cache
- * @param string $orderby
- * @return SiteTree The object with the given URL segment
+ * @deprecated 2.4 Use {@link SiteTree::get_by_link()}.
*/
- public static function get_by_url($urlSegment, $extraFilter = "", $cache = true, $orderby = "") {
- $filter = sprintf("\"URLSegment\" = '%s'", Convert::raw2sql($urlSegment));
- if($extraFilter) $filter .= " AND $extraFilter";
- $matchedPage = DataObject::get_one("SiteTree", $filter, $cache, $orderby);
- if($matchedPage) {
- return $matchedPage;
- } else {
- $alternativeMatches = singleton('SiteTree')->extend('alternateGetByUrl', $urlSegment, $extraFilter, $cache, $orderby);
- if($alternativeMatches) foreach($alternativeMatches as $alternativeMatch) {
- if($alternativeMatch) return $alternativeMatch;
- }
- return false;
- }
+ public static function get_by_url($link) {
+ user_error (
+ 'SiteTree::get_by_url() is deprecated, please use SiteTree::get_by_link()', E_USER_NOTICE
+ );
+
+ return self::get_by_link($link);
}
/**
diff --git a/tests/SiteTreeTest.php b/tests/SiteTreeTest.php
old mode 100644
new mode 100755
index 2209790fa..f955577e8
--- a/tests/SiteTreeTest.php
+++ b/tests/SiteTreeTest.php
@@ -272,20 +272,37 @@ class SiteTreeTest extends SapphireTest {
$this->assertEquals('Page', $requeriedPage->class);
}
-
- /**
- * Test SiteTree::get_by_url()
- */
- function testGetByURL() {
- // Test basic get by url
- $this->assertEquals($this->idFromFixture('Page', 'home'), SiteTree::get_by_url("home")->ID);
-
- // Test the extraFilter argument
- // Note: One day, it would be more appropriate to return null instead of false for queries such as these
- $this->assertFalse(SiteTree::get_by_url("home", "1 = 2"));
+
+ public function testGetByLink() {
+ $home = $this->objFromFixture('Page', 'home');
+ $about = $this->objFromFixture('Page', 'about');
+ $staff = $this->objFromFixture('Page', 'staff');
+ $product = $this->objFromFixture('Page', 'product1');
+ $notFound = $this->objFromFixture('ErrorPage', '404');
+
+ SiteTree::disable_nested_urls();
+
+ $this->assertEquals($home->ID, SiteTree::get_by_link('/', false)->ID);
+ $this->assertEquals($home->ID, SiteTree::get_by_link('/home/', false)->ID);
+ $this->assertEquals($about->ID, SiteTree::get_by_link($about->Link(), false)->ID);
+ $this->assertEquals($staff->ID, SiteTree::get_by_link($staff->Link(), false)->ID);
+ $this->assertEquals($product->ID, SiteTree::get_by_link($product->Link(), false)->ID);
+ $this->assertEquals($notFound->ID, SiteTree::get_by_link($notFound->Link(), false)->ID);
+
+ SiteTree::enable_nested_urls();
+
+ $this->assertEquals($home->ID, SiteTree::get_by_link('/', false)->ID);
+ $this->assertEquals($home->ID, SiteTree::get_by_link('/home/', false)->ID);
+ $this->assertEquals($about->ID, SiteTree::get_by_link($about->Link(), false)->ID);
+ $this->assertEquals($staff->ID, SiteTree::get_by_link($staff->Link(), false)->ID);
+ $this->assertEquals($product->ID, SiteTree::get_by_link($product->Link(), false)->ID);
+ $this->assertEquals($notFound->ID, SiteTree::get_by_link($notFound->Link(), false)->ID);
+
+ $this->assertEquals (
+ $staff->ID, SiteTree::get_by_link('/my-staff/', false)->ID, 'Assert a unique URLSegment can be used for b/c.'
+ );
}
-
function testDeleteFromStageOperatesRecursively() {
$pageAbout = $this->objFromFixture('Page', 'about');
$pageStaff = $this->objFromFixture('Page', 'staff');