From b8992866505021dbcbe465fc2d3be63f97ad150f Mon Sep 17 00:00:00 2001 From: Piotr Miazga Date: Tue, 4 Jun 2019 23:39:34 +0200 Subject: [PATCH] Encapsulate Login/profile/logout meny entry logic into AuthMenuEntry The Growth extension would like to override the the profile link in the main menu. We can replace the MenuEntry from group, but modifications of each component shouldn't be allowed. That approach is too much error prone. Furthermore it won't allow us to change how the Login/Logout link works. The Menu/Group accepts IMenuEntry objects, instead of building complicated Login/Logout menu entry, let's encapsulate all that logic into small, well-contained AuthMenuEntry object. Now, as we have the AuthMenuEntry, we can add an `overrideProfileURL' method to allow the profile url modifications. That approach will allow modify profile links, and "how to modify links" logic in one place. Changes: - extracted Definitions::insertLogInOutMenuItem() body into new AuthMenuEntry class - renamed some variables like $logoutUrl for better readability - introduced `AuthMenuEntry::overrideProfileUrl()` method that allows modification of the Profile url, label and tracking code. Bug: T222834 Change-Id: Ib7356acbd3373c7a4b591c9c133d7d02a55239b0 --- includes/menu/AuthMenuEntry.php | 206 ++++++++++++++++++++++++++++++++ includes/menu/Definitions.php | 67 +---------- 2 files changed, 212 insertions(+), 61 deletions(-) create mode 100644 includes/menu/AuthMenuEntry.php diff --git a/includes/menu/AuthMenuEntry.php b/includes/menu/AuthMenuEntry.php new file mode 100644 index 0000000..7c31944 --- /dev/null +++ b/includes/menu/AuthMenuEntry.php @@ -0,0 +1,206 @@ +user = $user; + $this->request = $request; + $this->title = $currentTitle; + $this->messageLocalizer = $messageLocalizer; + } + + /** + * @inheritDoc + */ + public function getName() { + return 'auth'; + } + + /** + * Override the href for the profile component for logged in users + * @param string $customURL A new href for profile entry + * @param string|null $customLabel A new label for profile entry. Null if you don't want to + * override it + * @param string $trackingCode new tracking code + */ + public function overrideProfileURL( $customURL, $customLabel = null, + $trackingCode = self::DEFAULT_PROFILE_TRACKING_CODE ) { + $this->customProfileURL = $customURL; + $this->customProfileLabel = $customLabel; + $this->profileTrackingCode = $trackingCode; + } + + /** + * @inheritDoc + */ + public function getCSSClasses(): array { + return []; + } + + /** + * @inheritDoc + */ + public function getComponents(): array { + $authLinksQuery = []; + $returnToQuery = $this->getReturnToQuery(); + + // Don't ever redirect back to the login page (bug 55379) + if ( $this->title && !$this->title->isSpecial( 'Userlogin' ) ) { + $authLinksQuery[ 'returnto' ] = $this->title->getPrefixedText(); + } + + return $this->user->isLoggedIn() + ? $this->buildComponentsForLoggedIn( $returnToQuery, $authLinksQuery ) + : $this->buildComponentsForAnon( $returnToQuery, $authLinksQuery ); + } + + /** + * Retrieve current query parameters from Request object so system can pass those + * to the Login/logout links + * Some parameters are disabled (like title), as the returnto will be replaced with + * the current page. + * @return array + */ + private function getReturnToQuery(): array { + $returnToQuery = []; + + if ( !$this->request->wasPosted() ) { + $returnToQuery = $this->request->getValues(); + unset( $returnToQuery['title'] ); + unset( $returnToQuery['returnto'] ); + unset( $returnToQuery['returntoquery'] ); + } + return $returnToQuery; + } + /** + * @param array $returnToQuery + * @param array $authLinksQuery + * @return array + * @throws \MWException + */ + private function buildComponentsForLoggedIn( array $returnToQuery, + array $authLinksQuery ): array { + if ( !empty( $returnToQuery ) ) { + $authLinksQuery['returntoquery'] = wfArrayToCgi( $returnToQuery ); + } + $logoutURL = SpecialPage::getTitleFor( 'Userlogout' )->getLocalURL( $authLinksQuery ); + $username = $this->user->getName(); + $profileUrl = $this->customProfileURL ?? + Title::newFromText( $username, NS_USER )->getLocalURL(); + $profileLabel = $this->customProfileLabel ?? $username; + + return [ + [ + 'text' => $profileLabel, + 'href' => $profileUrl, + 'class' => MinervaUI::iconClass( 'profile', 'before', + 'truncated-text primary-action' ), + 'data-event-name' => $this->profileTrackingCode + ], + [ + 'text' => $this->messageLocalizer->msg( 'mobile-frontend-main-menu-logout' )->escaped(), + 'href' => $logoutURL, + 'class' => MinervaUI::iconClass( 'logout', 'element', + 'truncated-text secondary-action' ), + 'data-event-name' => 'logout' + ] + ]; + } + + /** + * @param array $returnToQuery + * @param $authLinksQuery + * @return array + */ + private function buildComponentsForAnon( array $returnToQuery, $authLinksQuery ): array { + // unset campaign on login link so as not to interfere with A/B tests + unset( $returnToQuery['campaign'] ); + if ( !empty( $returntoquery ) ) { + $authLinksQuery['returntoquery'] = wfArrayToCgi( $returnToQuery ); + } + + return [ + 'text' => $this->messageLocalizer->msg( 'mobile-frontend-main-menu-login' )->escaped(), + 'href' => SpecialPage::getTitleFor( 'Userlogin' )->getLocalURL( $authLinksQuery ), + 'class' => MinervaUI::iconClass( 'login', 'before' ), + 'data-event-name' => 'login' + ]; + } + +} diff --git a/includes/menu/Definitions.php b/includes/menu/Definitions.php index fc776c3..8f6c9b8 100644 --- a/includes/menu/Definitions.php +++ b/includes/menu/Definitions.php @@ -117,56 +117,12 @@ final class Definitions { * @throws MWException */ public function insertLogInOutMenuItem( Group $group ) { - $query = []; - $returntoquery = []; - $request = $this->context->getRequest(); - - if ( !$request->wasPosted() ) { - $returntoquery = $request->getValues(); - unset( $returntoquery['title'] ); - unset( $returntoquery['returnto'] ); - unset( $returntoquery['returntoquery'] ); - } - $title = $this->context->getTitle(); - // Don't ever redirect back to the login page (bug 55379) - if ( !$title->isSpecial( 'Userlogin' ) ) { - $query[ 'returnto' ] = $title->getPrefixedText(); - } - - if ( $this->user->isLoggedIn() ) { - if ( !empty( $returntoquery ) ) { - $query[ 'returntoquery' ] = wfArrayToCgi( $returntoquery ); - } - $url = SpecialPage::getTitleFor( 'Userlogout' )->getLocalURL( $query ); - $username = $this->user->getName(); - - $group->insert( 'auth', false ) - ->addComponent( - $username, - Title::newFromText( $username, NS_USER )->getLocalURL(), - MinervaUI::iconClass( 'profile', 'before', 'truncated-text primary-action' ), - [ 'data-event-name' => 'profile' ] - ) - ->addComponent( - $this->context->msg( 'mobile-frontend-main-menu-logout' )->escaped(), - $url, - MinervaUI::iconClass( - 'logout', 'element', 'secondary-action truncated-text' ), - [ 'data-event-name' => 'logout' ] - ); - } else { - // unset campaign on login link so as not to interfere with A/B tests - unset( $returntoquery['campaign'] ); - $query[ 'returntoquery' ] = wfArrayToCgi( $returntoquery ); - $url = $this->getLoginUrl( $query ); - $group->insert( 'auth', false ) - ->addComponent( - $this->context->msg( 'mobile-frontend-main-menu-login' )->escaped(), - $url, - MinervaUI::iconClass( 'login', 'before' ), - [ 'data-event-name' => 'login' ] - ); - } + $group->insertEntry( new AuthMenuEntry( + $this->user, + $this->context->getRequest(), + $this->context, + $this->context->getTitle() + ) ); } /** @@ -322,15 +278,4 @@ final class Definitions { ); } - /** - * Prepares a url to the Special:UserLogin with query parameters - * - * @param array $query - * @return string - * @throws MWException - */ - private function getLoginUrl( $query ) { - return SpecialPage::getTitleFor( 'Userlogin' )->getLocalURL( $query ); - } - }