From ac4ff35dd40798167ac1deb0dd2d5e6ddb01e1c3 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Tue, 26 Apr 2016 16:12:05 +0200 Subject: [PATCH] Auto-generate breadcrumbs using page location --- .../lib/data/ITitledLinkObject.class.php | 15 +++++ .../files/lib/data/IUserContent.class.php | 2 +- .../files/lib/data/page/Page.class.php | 31 ++++++++-- .../files/lib/data/page/PageCache.class.php | 37 +++++++++++ .../files/lib/data/user/UserProfile.class.php | 28 +++++---- .../lib/form/AbstractModerationForm.class.php | 8 +-- .../install/files/lib/form/MailForm.class.php | 47 +++++++------- .../files/lib/form/UserSearchForm.class.php | 4 +- .../lib/page/RecentActivityListPage.class.php | 17 +++-- .../files/lib/page/SearchResultPage.class.php | 5 +- .../install/files/lib/page/TeamPage.class.php | 36 +++++------ .../install/files/lib/page/UserPage.class.php | 4 +- .../lib/page/UsersOnlineListPage.class.php | 6 +- .../system/breadcrumb/Breadcrumbs.class.php | 62 ++++++++++++++----- .../cache/builder/PageCacheBuilder.class.php | 18 ++++++ .../system/page/PageLocationManager.class.php | 39 ++++++++++-- .../system/request/ControllerMap.class.php | 4 +- 17 files changed, 259 insertions(+), 104 deletions(-) create mode 100644 wcfsetup/install/files/lib/data/ITitledLinkObject.class.php diff --git a/wcfsetup/install/files/lib/data/ITitledLinkObject.class.php b/wcfsetup/install/files/lib/data/ITitledLinkObject.class.php new file mode 100644 index 0000000000..f2f069b3bb --- /dev/null +++ b/wcfsetup/install/files/lib/data/ITitledLinkObject.class.php @@ -0,0 +1,15 @@ + + * @package com.woltlab.wcf + * @subpackage data + * @category Community Framework + * @since 2.2 + */ +interface ITitledLinkObject extends ILinkableObject, ITitledObject {} diff --git a/wcfsetup/install/files/lib/data/IUserContent.class.php b/wcfsetup/install/files/lib/data/IUserContent.class.php index 963da50d97..e33efa78e4 100644 --- a/wcfsetup/install/files/lib/data/IUserContent.class.php +++ b/wcfsetup/install/files/lib/data/IUserContent.class.php @@ -11,7 +11,7 @@ namespace wcf\data; * @subpackage data * @category Community Framework */ -interface IUserContent extends ILinkableObject, ITitledObject { +interface IUserContent extends ITitledLinkObject { /** * Returns message creation timestamp. * diff --git a/wcfsetup/install/files/lib/data/page/Page.class.php b/wcfsetup/install/files/lib/data/page/Page.class.php index d41980b233..42d7373003 100644 --- a/wcfsetup/install/files/lib/data/page/Page.class.php +++ b/wcfsetup/install/files/lib/data/page/Page.class.php @@ -1,6 +1,8 @@ * @package com.woltlab.wcf * @subpackage data.page @@ -39,7 +41,7 @@ use wcf\system\WCF; * @property-read string $permissions * @property-read string $options */ -class Page extends DatabaseObject { +class Page extends DatabaseObject implements ILinkableObject, ITitledObject { use TDatabaseObjectOptions; use TDatabaseObjectPermissions; @@ -146,9 +148,7 @@ class Page extends DatabaseObject { } /** - * Returns the page URL. - * - * @return string + * @inheritDoc */ public function getLink() { if ($this->controller) { @@ -167,6 +167,18 @@ class Page extends DatabaseObject { } } + /** + * @inheritDoc + */ + public function getTitle() { + $title = PageCache::getInstance()->getPageTitle($this->pageID); + if (empty($title)) { + $title = $this->getGenericTitle(); + } + + return $title; + } + /** * Returns shortened link for acp page list. * @@ -290,6 +302,15 @@ class Page extends DatabaseObject { return ''; } + /** + * Returns the value of a generic phrase based upon a page's identifier. + * + * @return string generic title + */ + protected function getGenericTitle() { + return WCF::getLanguage()->get('wcf.page.' . $this->identifier); + } + /** * Returns the page with the given identifier. * diff --git a/wcfsetup/install/files/lib/data/page/PageCache.class.php b/wcfsetup/install/files/lib/data/page/PageCache.class.php index b7fe00a97d..76f6ab734f 100644 --- a/wcfsetup/install/files/lib/data/page/PageCache.class.php +++ b/wcfsetup/install/files/lib/data/page/PageCache.class.php @@ -2,6 +2,7 @@ namespace wcf\data\page; use wcf\system\cache\builder\PageCacheBuilder; use wcf\system\SingletonFactory; +use wcf\system\WCF; /** * Provides access to the page cache. @@ -12,6 +13,7 @@ use wcf\system\SingletonFactory; * @package com.woltlab.wcf * @subpackage data.page * @category Community Framework + * @since 2.2 */ class PageCache extends SingletonFactory { /** @@ -68,4 +70,39 @@ class PageCache extends SingletonFactory { return null; } + + /** + * Returns the localized page title by page id, optionally retrieving the title + * for given language id if it is a multilingual page. + * + * @param integer $pageID page id + * @param integer $languageID specific value by language id + * @return string localized page title + */ + public function getPageTitle($pageID, $languageID = null) { + if (isset($this->cache['pageTitles'][$pageID])) { + $page = $this->getPage($pageID); + if ($page->isMultilingual) { + if ($languageID !== null && isset($this->cache['pageTitles'][$pageID][$languageID])) { + return $this->cache['pageTitles'][$pageID][$languageID]; + } + + return $this->cache['pageTitles'][$pageID][WCF::getUser()->getLanguage()->languageID]; + } + else { + return $this->cache['pageTitles'][$pageID][0]; + } + } + + return ''; + } + + /** + * Returns the global landing page. + * + * @return Page + */ + public function getLandingPage() { + return $this->cache['landingPage']; + } } diff --git a/wcfsetup/install/files/lib/data/user/UserProfile.class.php b/wcfsetup/install/files/lib/data/user/UserProfile.class.php index b1f6b158da..9e18a7283e 100644 --- a/wcfsetup/install/files/lib/data/user/UserProfile.class.php +++ b/wcfsetup/install/files/lib/data/user/UserProfile.class.php @@ -1,5 +1,6 @@ activationCode ? false : true); } - /** - * @inheritDoc - */ - public function getBreadcrumb() { - return new Breadcrumb($this->username, LinkHandler::getInstance()->getLink('User', [ - 'object' => $this - ])); - } - /** * Returns the encoded email address. * @@ -834,6 +824,20 @@ class UserProfile extends DatabaseObjectDecorator implements IBreadcrumbProvider return ''.StringUtil::encodeHTML($this->username).''; } + /** + * @inheritDoc + */ + public function getLink() { + return $this->getDecoratedObject()->getLink(); + } + + /** + * @inheritDoc + */ + public function getTitle() { + return $this->getDecoratedObject()->getTitle(); + } + /** * Returns an "empty" user profile object for a guest with the given username. * diff --git a/wcfsetup/install/files/lib/form/AbstractModerationForm.class.php b/wcfsetup/install/files/lib/form/AbstractModerationForm.class.php index 0ee986751d..104900393e 100644 --- a/wcfsetup/install/files/lib/form/AbstractModerationForm.class.php +++ b/wcfsetup/install/files/lib/form/AbstractModerationForm.class.php @@ -3,13 +3,12 @@ namespace wcf\form; use wcf\data\comment\StructuredCommentList; use wcf\data\moderation\queue\ModerationQueueAction; use wcf\data\moderation\queue\ViewableModerationQueue; -use wcf\system\breadcrumb\Breadcrumb; use wcf\system\comment\manager\ICommentManager; use wcf\system\comment\CommentHandler; use wcf\system\event\EventHandler; use wcf\system\exception\IllegalLinkException; use wcf\system\exception\PermissionDeniedException; -use wcf\system\request\LinkHandler; +use wcf\system\page\PageLocationManager; use wcf\system\WCF; /** @@ -102,10 +101,7 @@ abstract class AbstractModerationForm extends AbstractForm { $this->assignedUserID = $this->queue->assignedUserID; } - WCF::getBreadcrumbs()->add(new Breadcrumb( - WCF::getLanguage()->get('wcf.moderation.moderation'), - LinkHandler::getInstance()->getLink('ModerationList') - )); + PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.ModerationList'); $this->commentObjectTypeID = CommentHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.moderation.queue'); $this->commentManager = CommentHandler::getInstance()->getObjectType($this->commentObjectTypeID)->getProcessor(); diff --git a/wcfsetup/install/files/lib/form/MailForm.class.php b/wcfsetup/install/files/lib/form/MailForm.class.php index a9a31baa44..16b619ad64 100644 --- a/wcfsetup/install/files/lib/form/MailForm.class.php +++ b/wcfsetup/install/files/lib/form/MailForm.class.php @@ -6,6 +6,7 @@ use wcf\system\exception\IllegalLinkException; use wcf\system\exception\PermissionDeniedException; use wcf\system\exception\UserInputException; use wcf\system\mail\Mail; +use wcf\system\page\PageLocationManager; use wcf\system\request\LinkHandler; use wcf\system\WCF; use wcf\util\HeaderUtil; @@ -16,7 +17,7 @@ use wcf\util\UserUtil; * Shows the user mail form. * * @author Marcel Werk - * @copyright 2001-2015 WoltLab GmbH + * @copyright 2001-2016 WoltLab GmbH * @license GNU Lesser General Public License * @package com.woltlab.wcf * @subpackage form @@ -24,7 +25,7 @@ use wcf\util\UserUtil; */ class MailForm extends AbstractCaptchaForm { /** - * @see \wcf\form\AbstractCaptchaForm::$useCaptcha + * @inheritDoc */ public $useCaptcha = PROFILE_MAIL_USE_CAPTCHA; @@ -65,7 +66,12 @@ class MailForm extends AbstractCaptchaForm { public $email = ''; /** - * @see \wcf\page\IPage::readParameters() + * @inheritDoc + */ + public $neededPermissions = ['user.profile.canMail']; + + /** + * @inheritDoc */ public function readParameters() { parent::readParameters(); @@ -80,11 +86,11 @@ class MailForm extends AbstractCaptchaForm { throw new PermissionDeniedException(); } - $this->canonicalURL = LinkHandler::getInstance()->getLink('Mail', array('object' => $this->user->getDecoratedObject())); + $this->canonicalURL = LinkHandler::getInstance()->getLink('Mail', ['object' => $this->user->getDecoratedObject()]); } /** - * @see \wcf\form\IForm::readFormParameters() + * @inheritDoc */ public function readFormParameters() { parent::readFormParameters(); @@ -97,7 +103,7 @@ class MailForm extends AbstractCaptchaForm { } /** - * @see \wcf\form\IForm::validate() + * @inheritDoc */ public function validate() { if (!WCF::getUser()->userID) { @@ -122,7 +128,7 @@ class MailForm extends AbstractCaptchaForm { } /** - * @see \wcf\form\IForm::save() + * @inheritDoc */ public function save() { parent::save(); @@ -131,18 +137,18 @@ class MailForm extends AbstractCaptchaForm { $userLanguage = $this->user->getLanguage(); // build message data - $subjectData = array( + $subjectData = [ 'username' => WCF::getUser()->userID ? WCF::getUser()->username : $this->email, 'subject' => $this->subject - ); - $messageData = array( + ]; + $messageData = [ 'message' => $this->message, 'recipient' => $this->user, 'username' => WCF::getUser()->userID ? WCF::getUser()->username : $this->email, - ); + ]; // build mail - $mail = new Mail(array($this->user->username => $this->user->email), $userLanguage->getDynamicVariable('wcf.user.mail.mail.subject', $subjectData), $userLanguage->getDynamicVariable('wcf.user.mail.mail', $messageData)); + $mail = new Mail([$this->user->username => $this->user->email], $userLanguage->getDynamicVariable('wcf.user.mail.mail.subject', $subjectData), $userLanguage->getDynamicVariable('wcf.user.mail.mail', $messageData)); $mail->setLanguage($userLanguage); // add reply-to tag @@ -158,40 +164,39 @@ class MailForm extends AbstractCaptchaForm { $this->saved(); // forward to profile page - HeaderUtil::delayedRedirect(LinkHandler::getInstance()->getLink('User', array('object' => $this->user)), WCF::getLanguage()->getDynamicVariable('wcf.user.mail.sent', array('user' => $this->user))); + HeaderUtil::delayedRedirect(LinkHandler::getInstance()->getLink('User', ['object' => $this->user]), WCF::getLanguage()->getDynamicVariable('wcf.user.mail.sent', ['user' => $this->user])); exit; } /** - * @see \wcf\page\IPage::readData() + * @inheritDoc */ public function readData() { parent::readData(); - WCF::getBreadcrumbs()->add($this->user->getBreadcrumb()); + PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.User', $this->user->userID, $this->user); + if (MODULE_MEMBERS_LIST) PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.MembersList'); } /** - * @see \wcf\page\IPage::assignVariables() + * @inheritDoc */ public function assignVariables() { parent::assignVariables(); - WCF::getTPL()->assign(array( + WCF::getTPL()->assign([ 'user' => $this->user, 'showAddress' => $this->showAddress, 'message' => $this->message, 'subject' => $this->subject, 'email' => $this->email - )); + ]); } /** - * @see \wcf\page\IPage::show() + * @inheritDoc */ public function show() { - WCF::getSession()->checkPermissions(array('user.profile.canMail')); - if (!$this->user->isAccessible('canMail')) { throw new PermissionDeniedException(); } diff --git a/wcfsetup/install/files/lib/form/UserSearchForm.class.php b/wcfsetup/install/files/lib/form/UserSearchForm.class.php index 63b96114c9..0eecfc025b 100644 --- a/wcfsetup/install/files/lib/form/UserSearchForm.class.php +++ b/wcfsetup/install/files/lib/form/UserSearchForm.class.php @@ -2,9 +2,9 @@ namespace wcf\form; use wcf\acp\form\UserOptionListForm; use wcf\data\search\SearchEditor; -use wcf\system\breadcrumb\Breadcrumb; use wcf\system\database\util\PreparedStatementConditionBuilder; use wcf\system\exception\UserInputException; +use wcf\system\page\PageLocationManager; use wcf\system\request\LinkHandler; use wcf\system\WCF; use wcf\util\HeaderUtil; @@ -88,7 +88,7 @@ class UserSearchForm extends UserOptionListForm { $this->readOptionTree(); // add breadcrumbs - WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.user.members'), LinkHandler::getInstance()->getLink('MembersList'))); + if (MODULE_MEMBERS_LIST) PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.MembersList'); } /** diff --git a/wcfsetup/install/files/lib/page/RecentActivityListPage.class.php b/wcfsetup/install/files/lib/page/RecentActivityListPage.class.php index e43f301be1..9f05750800 100644 --- a/wcfsetup/install/files/lib/page/RecentActivityListPage.class.php +++ b/wcfsetup/install/files/lib/page/RecentActivityListPage.class.php @@ -1,8 +1,7 @@ * @package com.woltlab.wcf * @subpackage page @@ -19,12 +18,12 @@ use wcf\system\WCF; class RecentActivityListPage extends AbstractPage { /** * viewable user activity event list - * @var \wcf\data\user\activity\event\ViewableUserActivityEventList + * @var ViewableUserActivityEventList */ public $eventList = null; /** - * @see \wcf\page\IPage::readData() + * @inheritDoc */ public function readData() { parent::readData(); @@ -33,11 +32,11 @@ class RecentActivityListPage extends AbstractPage { $this->eventList->readObjects(); // add breadcrumbs - if (MODULE_MEMBERS_LIST) WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.user.members'), LinkHandler::getInstance()->getLink('MembersList'))); + if (MODULE_MEMBERS_LIST) PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.MembersList'); } /** - * @see \wcf\page\IPage::assignVariables() + * @inheritDoc */ public function assignVariables() { parent::assignVariables(); @@ -47,10 +46,10 @@ class RecentActivityListPage extends AbstractPage { // removes orphaned and non-accessable events UserActivityEventHandler::validateEvents($this->eventList); - WCF::getTPL()->assign(array( + WCF::getTPL()->assign([ 'eventList' => $this->eventList, 'lastEventTime' => $lastEventTime, 'allowSpidersToIndexThisPage' => true - )); + ]); } } diff --git a/wcfsetup/install/files/lib/page/SearchResultPage.class.php b/wcfsetup/install/files/lib/page/SearchResultPage.class.php index a011dd56e3..4d2143640f 100644 --- a/wcfsetup/install/files/lib/page/SearchResultPage.class.php +++ b/wcfsetup/install/files/lib/page/SearchResultPage.class.php @@ -3,11 +3,10 @@ namespace wcf\page; use wcf\data\search\ISearchResultObject; use wcf\data\search\Search; use wcf\system\application\ApplicationHandler; -use wcf\system\breadcrumb\Breadcrumb; use wcf\system\event\EventHandler; use wcf\system\exception\IllegalLinkException; use wcf\system\exception\SystemException; -use wcf\system\request\LinkHandler; +use wcf\system\page\PageLocationManager; use wcf\system\search\SearchEngine; use wcf\system\WCF; @@ -108,7 +107,7 @@ class SearchResultPage extends MultipleLinkPage { } // add breadcrumbs - WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.search.title'), LinkHandler::getInstance()->getLink('Search'))); + PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.Search'); } /** diff --git a/wcfsetup/install/files/lib/page/TeamPage.class.php b/wcfsetup/install/files/lib/page/TeamPage.class.php index 84d357f37d..3005e9ecbd 100644 --- a/wcfsetup/install/files/lib/page/TeamPage.class.php +++ b/wcfsetup/install/files/lib/page/TeamPage.class.php @@ -1,14 +1,14 @@ * @package com.woltlab.wcf * @subpackage page @@ -16,58 +16,58 @@ use wcf\system\WCF; */ class TeamPage extends MultipleLinkPage { /** - * @see \wcf\page\AbstractPage::$neededPermissions + * @inheritDoc */ - public $neededPermissions = array('user.profile.canViewMembersList'); + public $neededPermissions = ['user.profile.canViewMembersList']; /** - * @see \wcf\page\AbstractPage::$neededModules + * @inheritDoc */ - public $neededModules = array('MODULE_TEAM_PAGE'); + public $neededModules = ['MODULE_TEAM_PAGE']; /** - * @see \wcf\page\AbstractPage::$enableTracking + * @inheritDoc */ public $enableTracking = true; /** - * @see \wcf\page\MultipleLinkPage::$itemsPerPage + * @inheritDoc */ public $itemsPerPage = 1000; /** - * @see \wcf\page\MultipleLinkPage::$sortField + * @inheritDoc */ public $sortField = MEMBERS_LIST_DEFAULT_SORT_FIELD; /** - * @see \wcf\page\MultipleLinkPage::$sortOrder + * @inheritDoc */ public $sortOrder = MEMBERS_LIST_DEFAULT_SORT_ORDER; /** - * @see \wcf\page\MultipleLinkPage::$objectListClassName + * @inheritDoc */ - public $objectListClassName = 'wcf\data\user\TeamList'; + public $objectListClassName = TeamList::class; /** - * @see \wcf\page\IPage::readData() + * @inheritDoc */ public function readData() { parent::readData(); // add breadcrumbs - if (MODULE_MEMBERS_LIST) WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.user.members'), LinkHandler::getInstance()->getLink('MembersList'))); + if (MODULE_MEMBERS_LIST) PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.MembersList'); } /** - * @see \wcf\page\IPage::assignVariables() + * @inheritDoc */ public function assignVariables() { parent::assignVariables(); - WCF::getTPL()->assign(array( + WCF::getTPL()->assign([ 'allowSpidersToIndexThisPage' => true - )); + ]); } } diff --git a/wcfsetup/install/files/lib/page/UserPage.class.php b/wcfsetup/install/files/lib/page/UserPage.class.php index b2c870f5ca..64854dc230 100644 --- a/wcfsetup/install/files/lib/page/UserPage.class.php +++ b/wcfsetup/install/files/lib/page/UserPage.class.php @@ -9,11 +9,11 @@ use wcf\data\user\profile\visitor\UserProfileVisitorEditor; use wcf\data\user\profile\visitor\UserProfileVisitorList; use wcf\data\user\UserEditor; use wcf\data\user\UserProfile; -use wcf\system\breadcrumb\Breadcrumb; use wcf\system\cache\runtime\UserProfileRuntimeCache; use wcf\system\exception\IllegalLinkException; use wcf\system\exception\PermissionDeniedException; use wcf\system\menu\user\profile\UserProfileMenu; +use wcf\system\page\PageLocationManager; use wcf\system\request\LinkHandler; use wcf\system\MetaTagHandler; use wcf\system\WCF; @@ -110,7 +110,7 @@ class UserPage extends AbstractPage { parent::readData(); // add breadcrumbs - if (MODULE_MEMBERS_LIST) WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.user.members'), LinkHandler::getInstance()->getLink('MembersList'))); + if (MODULE_MEMBERS_LIST) PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.MembersList'); // get profile content if ($this->editOnInit) { diff --git a/wcfsetup/install/files/lib/page/UsersOnlineListPage.class.php b/wcfsetup/install/files/lib/page/UsersOnlineListPage.class.php index 528ed7e7e4..c906292cc4 100644 --- a/wcfsetup/install/files/lib/page/UsersOnlineListPage.class.php +++ b/wcfsetup/install/files/lib/page/UsersOnlineListPage.class.php @@ -3,8 +3,8 @@ namespace wcf\page; use wcf\data\page\PageCache; use wcf\data\user\online\UserOnline; use wcf\data\user\online\UsersOnlineList; -use wcf\system\breadcrumb\Breadcrumb; use wcf\system\page\handler\IOnlineLocationPageHandler; +use wcf\system\page\PageLocationManager; use wcf\system\request\LinkHandler; use wcf\system\WCF; use wcf\util\HeaderUtil; @@ -101,9 +101,7 @@ class UsersOnlineListPage extends SortablePage { parent::readData(); // add breadcrumbs - if (MODULE_MEMBERS_LIST) { - WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.user.members'), LinkHandler::getInstance()->getLink('MembersList'))); - } + if (MODULE_MEMBERS_LIST) PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.MembersList'); // cache all necessary data for showing locations foreach ($this->objectList as $userOnline) { diff --git a/wcfsetup/install/files/lib/system/breadcrumb/Breadcrumbs.class.php b/wcfsetup/install/files/lib/system/breadcrumb/Breadcrumbs.class.php index 39e49809d1..0994a605b9 100644 --- a/wcfsetup/install/files/lib/system/breadcrumb/Breadcrumbs.class.php +++ b/wcfsetup/install/files/lib/system/breadcrumb/Breadcrumbs.class.php @@ -1,5 +1,7 @@ items[] = $item; + throw new \BadMethodCallException("Breadcrumbs::add() is no longer supported, please use " . PageLocationManager::class . " instead."); } /** @@ -48,6 +51,10 @@ class Breadcrumbs extends SingletonFactory implements \Countable, \Iterator { * @return Breadcrumb[] */ public function get() { + if ($this->items === null) { + $this->loadBreadcrumbs(); + } + return $this->items; } @@ -57,15 +64,10 @@ class Breadcrumbs extends SingletonFactory implements \Countable, \Iterator { * @param Breadcrumb $item * @param integer $index * @return boolean + * @deprecated 2.2 */ public function replace(Breadcrumb $item, $index) { - if (isset($this->items[$index])) { - $this->items[$index] = $item; - - return true; - } - - return false; + throw new \BadMethodCallException("Breadcrumbs::replace() is no longer supported, please use " . PageLocationManager::class . " instead."); } /** @@ -73,21 +75,53 @@ class Breadcrumbs extends SingletonFactory implements \Countable, \Iterator { * * @param integer $index * @return boolean + * @deprecated 2.2 */ public function remove($index) { - if (isset($this->items[$index])) { - unset($this->items[$index]); - - return true; + throw new \BadMethodCallException("Breadcrumbs::remove() is no longer supported, please use " . PageLocationManager::class . " instead."); + } + + protected function loadBreadcrumbs() { + $this->items = []; + $locations = PageLocationManager::getInstance()->getLocations(); + + // locations are provided starting with the current location followed + // by all relevant ancestors, but breadcrumbs appear in the reverse order + $locations = array_reverse($locations); + + // add the landing page as first location, unless it is already included + $landingPage = PageCache::getInstance()->getLandingPage(); + $addLandingPage = true; + for ($i = 0, $length = count($locations); $i < $length; $i++) { + if ($locations[$i]['pageID'] == $landingPage->pageID) { + $addLandingPage = false; + break; + } + } + + if ($addLandingPage) { + array_unshift($locations, [ + 'link' => $landingPage->getLink(), + 'title' => $landingPage->getTitle() + ]); } - return false; + // ignore the last location as it represents the current page + array_pop($locations); + + for ($i = 0, $length = count($locations); $i < $length; $i++) { + $this->items[] = new Breadcrumb($locations[$i]['title'], $locations[$i]['link']); + } } /** * @inheritDoc */ public function count() { + if ($this->items === null) { + $this->loadBreadcrumbs(); + } + return count($this->items); } diff --git a/wcfsetup/install/files/lib/system/cache/builder/PageCacheBuilder.class.php b/wcfsetup/install/files/lib/system/cache/builder/PageCacheBuilder.class.php index 6447f21216..6eaedf88e4 100644 --- a/wcfsetup/install/files/lib/system/cache/builder/PageCacheBuilder.class.php +++ b/wcfsetup/install/files/lib/system/cache/builder/PageCacheBuilder.class.php @@ -2,6 +2,7 @@ namespace wcf\system\cache\builder; use wcf\data\page\Page; use wcf\data\page\PageList; +use wcf\system\WCF; /** * Caches the page data. @@ -12,6 +13,7 @@ use wcf\data\page\PageList; * @package com.woltlab.wcf * @subpackage system.cache.builder * @category Community Framework + * @since 2.2 */ class PageCacheBuilder extends AbstractCacheBuilder { /** @@ -22,6 +24,7 @@ class PageCacheBuilder extends AbstractCacheBuilder { 'identifier' => [], 'controller' => [], 'pages' => [], + 'pageTitles' => [], 'landingPage' => null ]; @@ -29,6 +32,21 @@ class PageCacheBuilder extends AbstractCacheBuilder { $pageList->readObjects(); $data['pages'] = $pageList->getObjects(); + // get page titles + $sql = "SELECT pageID, languageID, title + FROM wcf".WCF_N."_page_content"; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute(); + while ($row = $statement->fetchArray()) { + $pageID = $row['pageID']; + + if (!isset($data['pageTitles'])) { + $data['pageTitles'][$pageID] = []; + } + + $data['pageTitles'][$pageID][$row['languageID'] ?: 0] = $row['title']; + } + // build lookup table /** @var Page $page */ foreach ($pageList as $page) { diff --git a/wcfsetup/install/files/lib/system/page/PageLocationManager.class.php b/wcfsetup/install/files/lib/system/page/PageLocationManager.class.php index 98a99b36a0..31e2e80eb3 100644 --- a/wcfsetup/install/files/lib/system/page/PageLocationManager.class.php +++ b/wcfsetup/install/files/lib/system/page/PageLocationManager.class.php @@ -1,5 +1,6 @@ getMetaData(); + $link = $title = ''; + $page = null; if (isset($metaData['cms'])) { $pageID = $metaData['cms']['pageID']; + + $page = PageCache::getInstance()->getPage($pageID); } else { $page = PageCache::getInstance()->getPageByController($activeRequest->getClassName()); @@ -48,8 +54,11 @@ class PageLocationManager extends SingletonFactory { if ($pageID !== null) { $this->stack[] = [ + 'identifier' => $page->identifier, + 'link' => $page->getLink(), 'pageID' => $pageID, - 'pageObjectID' => $pageObjectID + 'pageObjectID' => $pageObjectID, + 'title' => $page->getTitle() ]; } } @@ -58,19 +67,39 @@ class PageLocationManager extends SingletonFactory { * Appends a parent location to the stack, the later it is added the lower * is its assumed priority when matching suitable menu items. * - * @param string $identifier internal page identifier - * @param integer $pageObjectID page object id + * @param string $identifier internal page identifier + * @param integer $pageObjectID page object id + * @param ITitledLinkObject $locationObject optional label for breadcrumbs usage * @throws SystemException */ - public function addParentLocation($identifier, $pageObjectID = 0) { + public function addParentLocation($identifier, $pageObjectID = 0, ITitledLinkObject $locationObject = null) { $page = PageCache::getInstance()->getPageByIdentifier($identifier); if ($page === null) { throw new SystemException("Unknown page identifier '".$identifier."'."); } + // check if the provided location is already part of the stack + for ($i = 0, $length = count($this->stack); $i < $length; $i++) { + if ($this->stack[$i]['identifier'] == $identifier && $this->stack[$i]['pageObjectID'] == $pageObjectID) { + return; + } + } + + if ($locationObject !== null) { + $link = $locationObject->getLink(); + $title = $locationObject->getTitle(); + } + else { + $link = $page->getLink(); + $title = $page->getTitle(); + } + $this->stack[] = [ + 'identifier' => $identifier, + 'link' => $link, 'pageID' => $page->pageID, - 'pageObjectID' => $pageObjectID + 'pageObjectID' => $pageObjectID, + 'title' => $title ]; } diff --git a/wcfsetup/install/files/lib/system/request/ControllerMap.class.php b/wcfsetup/install/files/lib/system/request/ControllerMap.class.php index dca618a7f3..9aaf799a4d 100644 --- a/wcfsetup/install/files/lib/system/request/ControllerMap.class.php +++ b/wcfsetup/install/files/lib/system/request/ControllerMap.class.php @@ -10,7 +10,7 @@ use wcf\system\WCF; * Resolves incoming requests and performs lookups for controller to url mappings. * * @author Alexander Ebert - * @copyright 2001-2015 WoltLab GmbH + * @copyright 2001-2016 WoltLab GmbH * @license GNU Lesser General Public License * @package com.woltlab.wcf * @subpackage system.request @@ -57,7 +57,7 @@ class ControllerMap extends SingletonFactory { * @param string $application application identifier * @param string $controller url controller * @param boolean $isAcpRequest true if this is an ACP request - * @return mixed array containing className, controller and pageType or a string containing the controller name for aliased controllers + * @return mixed array containing className, controller and pageType or a string containing the controller name for aliased controllers * @throws SystemException */ public function resolve($application, $controller, $isAcpRequest) { -- 2.20.1