From 1c5e737d06523136f98b9f34b882043ba792d6d1 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Fri, 18 Jan 2013 10:49:32 +1300 Subject: [PATCH] API register_routes() for registering custom paths. This replaces the existing updateItems() + extension hook in favour of consistency with the register_dataobject() interface. Note that this will likely be superseded by something to do with the Config API in the future. --- code/GoogleSitemap.php | 103 +++++++++++++++++++++++++++++++++++- docs/en/index.md | 15 +++++- tests/GoogleSitemapTest.php | 38 +++++++++++++ 3 files changed, 153 insertions(+), 3 deletions(-) diff --git a/code/GoogleSitemap.php b/code/GoogleSitemap.php index 2d077d3..adf4451 100644 --- a/code/GoogleSitemap.php +++ b/code/GoogleSitemap.php @@ -29,13 +29,21 @@ class GoogleSitemap { /** - * List of DataObject class names to include. As well as the change + * List of {@link DataObject} class names to include. As well as the change * frequency and priority of each class. * * @var array */ private static $dataobjects = array(); + /** + * List of custom routes to include in the sitemap (such as controller + * subclasses) as well as the change frequency and priority. + * + * @var array + */ + private static $routes = array(); + /** * Decorates the given DataObject with {@link GoogleSitemapDecorator} * and pushes the class name to the registered DataObjects. @@ -61,6 +69,25 @@ class GoogleSitemap { } } + /** + * Registers multiple dataobjects in a single line. See {@link register_dataobject} + * for the heavy lifting + * + * @param array $dataobjects array of class names of DataObject to register + * @param string $changeFreq how often is this DataObject updated? + * Possible values: + * always, hourly, daily, weekly, monthly, yearly, never + * @param string $priority How important is this DataObject in comparison to other urls? + * Possible values: 0.1, 0.2 ... , 0.9, 1.0 + * + * @return void + */ + public static function register_dataobjects($dataobjects, $changeFreq = 'monthly', $priority = '0.6') { + foreach($dataobjects as $obj) { + self::register_dataobject($obj, $changeFreq, $priority); + } + } + /** * Checks whether the given class name is already registered or not. * @@ -83,11 +110,56 @@ class GoogleSitemap { /** * Clears registered {@link DataObjects}. Useful for unit tests. + * + * @return void */ public static function clear_registered_dataobjects() { self::$dataobjects = array(); } + /** + * Register a given route to the sitemap list + * + * @param string + * @param string + * @param string + * + * @return void + */ + public static function register_route($route, $changeFreq = 'monthly', $priority = '0.6') { + self::$routes = array_merge(self::$routes, array( + $route => array( + 'frequency' => ($changeFreq) ? $changeFreq : 'monthly', + 'priority' => ($priority) ? $priority : '0.6' + ) + )); + } + + /** + * Registers a given list of relative urls. Will be merged with the current + * registered routes. If you want to replace them, please call {@link clear_routes} + * + * @param array + * @param string + * @param string + * + * @return void + */ + public static function register_routes($routes, $changeFreq = 'monthly', $priority = '0.6') { + foreach($routes as $route) { + self::register_route($route, $changeFreq, $priority); + } + } + + /** + * Clears registered routes + * + * @return void + */ + public static function clear_registered_routes() { + self::$routes = array(); + } + /** * Constructs the list of data to include in the rendered sitemap. Links * can include pages from the website, dataobjects (such as forum posts) @@ -107,6 +179,22 @@ class GoogleSitemap { $filter = ($filter) ? "\"ShowInSearch\" = 1" : ""; $instances = Versioned::get_by_stage('SiteTree', 'Live', $filter); } + else if($class == "GoogleSitemapRoute") { + $instances = array_slice(self::$routes, ($page - 1) * $count, $count); + $output = new ArrayList(); + + if($instances) { + foreach($instances as $route => $config) { + $output->push(new ArrayData(array( + 'AbsoluteLink' => Director::absoluteURL($route), + 'ChangeFrequency' => $config['frequency'], + 'GooglePriority' => $config['priority'] + ))); + } + } + + return $output; + } else { $instances = new DataList($class); } @@ -196,7 +284,7 @@ class GoogleSitemap { } } - if(self::$dataobjects) { + if(count(self::$dataobjects) > 0) { foreach(self::$dataobjects as $class => $config) { $list = new DataList($class); $list = $list->sort('LastEdited ASC'); @@ -220,6 +308,17 @@ class GoogleSitemap { } } + if(count(self::$routes) > 0) { + $needed = ceil(count(self::$routes) / $countPerFile); + + for($i = 1; $i <= $needed; $i++) { + $sitemaps->push(new ArrayData(array( + 'ClassName' => 'GoogleSitemapRoute', + 'Page' => $i + ))); + } + } + return $sitemaps; } diff --git a/docs/en/index.md b/docs/en/index.md index 3a7fca0..4f06081 100644 --- a/docs/en/index.md +++ b/docs/en/index.md @@ -103,4 +103,17 @@ instead of the previous code you would write: See the following blog post for more information: -http://www.silvercart.org/blog/dataobjects-and-googlesitemaps/ \ No newline at end of file +http://www.silvercart.org/blog/dataobjects-and-googlesitemaps/ + +### Including custom routes + +Occasionally you may have a need to include custom url's in your sitemap for +your Controllers and other pages which don't exist in the database. To update +the sitemap to include those links call register_routes() with your array of +urls to include. + + GoogleSitemap::register_routes(array( + '/my-custom-controller/', + '/Security/', + '/Security/login/' + )); diff --git a/tests/GoogleSitemapTest.php b/tests/GoogleSitemapTest.php index c6ac7cf..6b0c123 100644 --- a/tests/GoogleSitemapTest.php +++ b/tests/GoogleSitemapTest.php @@ -22,12 +22,24 @@ class GoogleSitemapTest extends FunctionalTest { } GoogleSitemap::clear_registered_dataobjects(); + GoogleSitemap::clear_registered_routes(); } public function tearDown() { parent::tearDown(); GoogleSitemap::clear_registered_dataobjects(); + GoogleSitemap::clear_registered_routes(); + } + + public function testIndexFileWithCustomRoute() { + GoogleSitemap::register_route('/test/'); + + $response = $this->get('sitemap.xml'); + $body = $response->getBody(); + + $expected = "". Director::absoluteURL("sitemap.xml/sitemap/GoogleSitemapRoute/1") .""; + $this->assertEquals(1, substr_count($body, $expected) , 'A link to the custom routes exists'); } @@ -49,6 +61,17 @@ class GoogleSitemapTest extends FunctionalTest { $this->assertEquals(0, GoogleSitemap::get_items('GoogleSitemapTest_UnviewableDataObject', 1)->count()); } + public function testGetItemsWithCustomRoutes() { + GoogleSitemap::register_routes(array( + '/test-route/', + '/someother-route/', + '/fake-sitemap-route/' + )); + + $items = GoogleSitemap::get_items('GoogleSitemapRoute', 1); + $this->assertEquals(3, $items->count()); + } + public function testAccessingSitemapRootXMLFile() { GoogleSitemap::register_dataobject("GoogleSitemapTest_DataObject"); GoogleSitemap::register_dataobject("GoogleSitemapTest_OtherDataObject"); @@ -98,6 +121,21 @@ class GoogleSitemapTest extends FunctionalTest { Config::inst()->update('GoogleSitemap', 'objects_per_sitemap', $original); } + public function testRegisterRoutesIncludesAllRoutes() { + GoogleSitemap::register_route('/test/'); + GoogleSitemap::register_routes(array( + '/test/', // duplication should be replaced + '/unittests/', + '/anotherlink/' + ), 'weekly'); + + $response = $this->get('sitemap.xml/sitemap/GoogleSitemapRoute/1'); + $body = $response->getBody(); + + $this->assertEquals(200, $response->getStatusCode(), 'successful loaded nested sitemap'); + $this->assertEquals(3, substr_count($body, "")); + } + public function testAccessingNestedSiteMap() { $original = Config::inst()->get('GoogleSitemap', 'objects_per_sitemap'); Config::inst()->update('GoogleSitemap', 'objects_per_sitemap', 1);