From e13537e0a7b141138763088cc19984644a562c17 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 15 Jul 2011 16:05:58 +0200 Subject: [PATCH] API CHANGE Refactored SilverStripeNavigator and SilverStripeNavigatorItem to instance-based utility classes, which take a DataObject record in the constructor rather than all of their methods (increasing template flexibility and code isolation). ENHANCEMENT Added SilverStripeNavigatorItem->canView() for flexible permission control MINOR Fixed duplicate priority overrides in SilverStripeNavigator MINOR Removed unnecessary inline styling from SilverStripeNavigator HTML generation --- code/controller/SilverStripeNavigator.php | 277 ++++++++++++++++++ code/controller/SilverStripeNavigatorItem.php | 189 ------------ .../controller/SilverStripeNavigatorTest.php | 54 ++++ 3 files changed, 331 insertions(+), 189 deletions(-) create mode 100644 code/controller/SilverStripeNavigator.php delete mode 100644 code/controller/SilverStripeNavigatorItem.php create mode 100644 tests/controller/SilverStripeNavigatorTest.php diff --git a/code/controller/SilverStripeNavigator.php b/code/controller/SilverStripeNavigator.php new file mode 100644 index 00000000..f81c6c73 --- /dev/null +++ b/code/controller/SilverStripeNavigator.php @@ -0,0 +1,277 @@ +record = $record; + } + + /** + * @return DataObjectSet of SilverStripeNavigatorItem + */ + function getItems() { + $items = ''; + + $classes = ClassInfo::subclassesFor('SilverStripeNavigatorItem'); + array_shift($classes); + + // Sort menu items according to priority + $i = 0; + foreach($classes as $class) { + // Skip base class + if($class == 'SilverStripeNavigatorItem') continue; + + $i++; + $item = new $class($this->record); + if(!$item->canView()) continue; + + // This funny litle formula ensures that the first item added with the same priority will be left-most. + $priority = $item->getPriority() * 100 - 1; + + // Ensure that we can have duplicates with the same (default) priority + while(isset($items[$priority])) $priority++; + + $items[$priority] = $item; + } + ksort($items); + + return new DataObjectSet($items); + } + + /** + * @return DataObject + */ + function getRecord() { + return $this->record; + } + + /** + * @param SiteTree $record + * @return Array template data + */ + static function get_for_record($record) { + $html = ''; + $message = ''; + $navigator = new SilverStripeNavigator($record); + $items = $navigator->getItems(); + foreach($items as $item) { + $text = $item->getHTML(); + if($text) $html .= $text; + $newMessage = $item->getMessage(); + if($newMessage) $message = $newMessage; + } + + return array( + 'items' => $html, + 'message' => $message + ); + } +} + +/** + * Navigator items are links that appear in the $SilverStripeNavigator bar. + * To add an item, extends this class. + * + * @package cms + * @subpackage content + */ +class SilverStripeNavigatorItem extends ViewableData { + + /** + * @param DataObject + */ + protected $record; + + /** + * @param DataObject + */ + function __construct($record) { + $this->record = $record; + } + + /** + * @return String HTML, mostly a link - but can be more complex as well. + * For example, a "future state" item might show a date selector. + * Hence there's no getLink() method. + */ + function getHTML() {} + + /** + * @return String + */ + function getMessage() {} + + /** + * @return DataObject + */ + function getRecord() { + return $this->record; + } + + /** + * @return Int + */ + function getPriority() { + return $this->stat('priority'); + } + + /** + * Filters items based on member permissions or other criteria. + * + * @param Member + * @return Boolean + */ + function canView($member = null) { + return true; + } +} + +/** + * @package cms + * @subpackage content + */ +class SilverStripeNavigatorItem_CMSLink extends SilverStripeNavigatorItem { + static $priority = 10; + + function getHTML() { + if(is_a(Controller::curr(), 'CMSMain')) { + return 'CMS'; + } else { + $cmsLink = 'admin/show/' . $this->record->ID; + $cmsLink = "". _t('ContentController.CMS', 'CMS') .""; + + return $cmsLink; + } + } + + function getLink() { + if(is_a(Controller::curr(), 'CMSMain')) { + return Controller::curr()->AbsoluteLink('show') . $this->record->ID; + } + } + +} + +/** + * @package cms + * @subpackage content + */ +class SilverStripeNavigatorItem_StageLink extends SilverStripeNavigatorItem { + static $priority = 20; + + function getHTML() { + if(Versioned::current_stage() == 'Stage' && !(ClassInfo::exists('SiteTreeFutureState') && SiteTreeFutureState::get_future_datetime())) { + return "". _t('ContentController.DRAFTSITE', 'Draft Site') .""; + } else { + $draftPage = Versioned::get_one_by_stage('SiteTree', 'Stage', '"SiteTree"."ID" = ' . $this->record->ID); + if($draftPage) { + $this->recordLink = Controller::join_links($draftPage->AbsoluteLink(), "?stage=Stage"); + return "recordLink\">". _t('ContentController.DRAFTSITE', 'Draft Site') .""; + } + } + } + + function getMessage() { + if(Versioned::current_stage() == 'Stage') { + return "
". _t('ContentController.DRAFTSITE', 'Draft Site') ."
"; + } + } + + function getLink() { + if(Versioned::current_stage() == 'Stage') { + return Controller::join_links($this->record->AbsoluteLink(), '?stage=Stage'); + } + } +} + +/** + * @package cms + * @subpackage content + */ +class SilverStripeNavigatorItem_LiveLink extends SilverStripeNavigatorItem { + static $priority = 30; + + function getHTML() { + if(Versioned::current_stage() == 'Live') { + return "". _t('ContentController.PUBLISHEDSITE', 'Published Site') .""; + } else { + $livePage = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $this->record->ID); + if($livePage) { + $this->recordLink = Controller::join_links($livePage->AbsoluteLink(), "?stage=Live"); + return "recordLink\">". _t('ContentController.PUBLISHEDSITE', 'Published Site') .""; + } + } + } + + function getMessage() { + if(Versioned::current_stage() == 'Live') { + return "
". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."
"; + } + } + + function getLink() { + if(Versioned::current_stage() == 'Live') { + return Controller::join_links($this->record->AbsoluteLink(), '?stage=Live'); + } + } +} + +/** + * @package cms + * @subpackage content + */ +class SilverStripeNavigatorItem_ArchiveLink extends SilverStripeNavigatorItem { + static $priority = 40; + + function getHTML() { + if(Versioned::current_archived_date()) { + return "". _t('ContentController.ARCHIVEDSITE', 'Archived Site') .""; + } else { + // Display the archive link if the page currently displayed in the CMS is other version than live and draft + $currentDraft = Versioned::get_one_by_stage('SiteTree', 'Draft', '"SiteTree"."ID" = ' . $this->record->ID); + $currentLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $this->record->ID); + if( + (!$currentDraft || ($currentDraft && $this->record->Version != $currentDraft->Version)) + && (!$currentLive || ($currentLive && $this->record->Version != $currentLive->Version)) + ) { + $this->recordLink = $this->record->AbsoluteLink(); + return "recordLink?archiveDate={$this->record->LastEdited}\" target=\"_blank\">". _t('ContentController.ARCHIVEDSITE', 'Archived Site') .""; + } + } + } + + function getMessage() { + if($date = Versioned::current_archived_date()) { + $dateObj = Object::create('Datetime'); + $dateObj->setValue($date); + return "
". _t('ContentController.ARCHIVEDSITEFROM', 'Archived site from') ."
" . $dateObj->Nice() . "
"; + } + } + + function getLink() { + if($date = Versioned::current_archived_date()) { + return $this->record->AbsoluteLink() . '?archiveDate=' . $date; + } + } +} + +?> \ No newline at end of file diff --git a/code/controller/SilverStripeNavigatorItem.php b/code/controller/SilverStripeNavigatorItem.php deleted file mode 100644 index 762e3988..00000000 --- a/code/controller/SilverStripeNavigatorItem.php +++ /dev/null @@ -1,189 +0,0 @@ -getHTML($record); - if($text) $items .= $text; - $newMessage = $obj->getMessage($record); - if($newMessage) $message = $newMessage; - } - - return array( - 'items' => $items, - 'message' => $message - ); - } -} - -/** - * Navigator items are links that appear in the $SilverStripeNavigator bar. - * To add an item, extends this class. - * - * @package cms - * @subpackage content - */ -class SilverStripeNavigatorItem extends Object { - function getHTML($page) {} - function getMessage($page) {} -} - -/** - * @package cms - * @subpackage content - */ -class SilverStripeNavigatorItem_CMSLink extends SilverStripeNavigatorItem { - static $priority = 10; - - function getHTML($page) { - if(is_a(Controller::curr(), 'CMSMain')) { - return 'CMS'; - } else { - $cmsLink = 'admin/show/' . $page->ID; - $cmsLink = "". _t('ContentController.CMS', 'CMS') .""; - - return $cmsLink; - } - } - - function getLink($page) { - if(is_a(Controller::curr(), 'CMSMain')) { - return Controller::curr()->AbsoluteLink('show') . $page->ID; - } - } - -} - -/** - * @package cms - * @subpackage content - */ -class SilverStripeNavigatorItem_StageLink extends SilverStripeNavigatorItem { - static $priority = 20; - - function getHTML($page) { - if(Versioned::current_stage() == 'Stage' && !(ClassInfo::exists('SiteTreeFutureState') && SiteTreeFutureState::get_future_datetime())) { - return "". _t('ContentController.DRAFTSITE', 'Draft Site') .""; - } else { - $draftPage = Versioned::get_one_by_stage('SiteTree', 'Stage', '"SiteTree"."ID" = ' . $page->ID); - if($draftPage) { - $pageLink = Controller::join_links($draftPage->AbsoluteLink(), "?stage=Stage"); - return "". _t('ContentController.DRAFTSITE', 'Draft Site') .""; - } - } - } - - function getMessage($page) { - if(Versioned::current_stage() == 'Stage') { - return "
". _t('ContentController.DRAFTSITE', 'Draft Site') ."
"; - } - } - - function getLink($page) { - if(Versioned::current_stage() == 'Stage') { - return Controller::join_links($page->AbsoluteLink(), '?stage=Stage'); - } - } -} - -/** - * @package cms - * @subpackage content - */ -class SilverStripeNavigatorItem_LiveLink extends SilverStripeNavigatorItem { - static $priority = 30; - - function getHTML($page) { - if(Versioned::current_stage() == 'Live') { - return "". _t('ContentController.PUBLISHEDSITE', 'Published Site') .""; - } else { - $livePage = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $page->ID); - if($livePage) { - $pageLink = Controller::join_links($livePage->AbsoluteLink(), "?stage=Live"); - return "". _t('ContentController.PUBLISHEDSITE', 'Published Site') .""; - } - } - } - - function getMessage($page) { - if(Versioned::current_stage() == 'Live') { - return "
". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."
"; - } - } - - function getLink($page) { - if(Versioned::current_stage() == 'Live') { - return Controller::join_links($page->AbsoluteLink(), '?stage=Live'); - } - } -} - -/** - * @package cms - * @subpackage content - */ -class SilverStripeNavigatorItem_ArchiveLink extends SilverStripeNavigatorItem { - static $priority = 40; - - function getHTML($page) { - if(Versioned::current_archived_date()) { - return "". _t('ContentController.ARCHIVEDSITE', 'Archived Site') .""; - } else { - // Display the archive link if the page currently displayed in the CMS is other version than live and draft - $currentDraft = Versioned::get_one_by_stage('SiteTree', 'Draft', '"SiteTree"."ID" = ' . $page->ID); - $currentLive = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $page->ID); - if( - (!$currentDraft || ($currentDraft && $page->Version != $currentDraft->Version)) - && (!$currentLive || ($currentLive && $page->Version != $currentLive->Version)) - ) { - $pageLink = $page->AbsoluteLink(); - return "LastEdited}\" class=\"newWindow\" target=\"site\" style=\"left : -3px;\">". _t('ContentController.ARCHIVEDSITE', 'Archived Site') .""; - } - } - } - - function getMessage($page) { - if($date = Versioned::current_archived_date()) { - $dateObj = Object::create('Datetime'); - $dateObj->setValue($date); - return "
". _t('ContentController.ARCHIVEDSITEFROM', 'Archived site from') ."
" . $dateObj->Nice() . "
"; - } - } - - function getLink($page) { - if($date = Versioned::current_archived_date()) { - return $page->AbsoluteLink() . '?archiveDate=' . $date; - } - } -} - -?> \ No newline at end of file diff --git a/tests/controller/SilverStripeNavigatorTest.php b/tests/controller/SilverStripeNavigatorTest.php new file mode 100644 index 00000000..033ec6cd --- /dev/null +++ b/tests/controller/SilverStripeNavigatorTest.php @@ -0,0 +1,54 @@ +objFromFixture('Page', 'page1'); + $navigator = new SilverStripeNavigator($page); + + $items = $navigator->getItems(); + $classes = array_map('get_class', $items->toArray()); + $this->assertContains('SilverStripeNavigatorItem_LiveLink', $classes, + 'Adds default classes' + ); + + $this->assertContains('SilverStripeNavigatorTest_TestItem', $classes, + 'Autodiscovers new classes' + ); + } + + function testCanView() { + $page = $this->objFromFixture('Page', 'page1'); + $admin = $this->objFromFixture('Member', 'admin'); + $author = $this->objFromFixture('Member', 'assetsonlyuser'); + $navigator = new SilverStripeNavigator($page); + + // TODO Shouldn't be necessary but SapphireTest logs in as ADMIN by default + $this->logInWithPermission('CMS_ACCESS_AssetAdmin'); + $items = $navigator->getItems(); + $classes = array_map('get_class', $items->toArray()); + $this->assertNotContains('SilverStripeNavigatorTest_ProtectedTestItem', $classes); + + $this->logInWithPermission('ADMIN'); + $items = $navigator->getItems(); + $classes = array_map('get_class', $items->toArray()); + $this->assertContains('SilverStripeNavigatorTest_ProtectedTestItem', $classes); + } + +} + +class SilverStripeNavigatorTest_TestItem extends SilverStripeNavigatorItem implements TestOnly { +} + +class SilverStripeNavigatorTest_ProtectedTestItem extends SilverStripeNavigatorItem implements TestOnly { + function canView($member = null) { + if(!$member) $member = Member::currentUser(); + return Permission::checkMember($member, 'ADMIN'); + } +} \ No newline at end of file