Commit 2b8e5590 authored by webchick's avatar webchick

Issue #2503755 by Wim Leers, bobrov1989, webchick, dcrocks, andypost,...

Issue #2503755 by Wim Leers, bobrov1989, webchick, dcrocks, andypost, emma.maria, catch, Bojhan, dawehner, Gábor Hojtsy, alexpott, tstoeckler, yoroy: Switch from user login block to login menu link and search block in standard profile
parent b6707fca
......@@ -206,15 +206,14 @@ protected function menuLinkCheckAccess(MenuLinkInterface $instance) {
$access_result = AccessResult::allowed();
}
else {
// Use the definition here since that's a lot faster than creating a Url
// object that we don't need.
$definition = $instance->getPluginDefinition();
// 'url' should only be populated for external links.
if (!empty($definition['url']) && empty($definition['route_name'])) {
$url = $instance->getUrlObject();
// When no route name is specified, this must be an external link.
if (!$url->isRouted()) {
$access_result = AccessResult::allowed();
}
else {
$access_result = $this->accessManager->checkNamedRoute($definition['route_name'], $definition['route_parameters'], $this->account, TRUE);
$access_result = $this->accessManager->checkNamedRoute($url->getRouteName(), $url->getRouteParameters(), $this->account, TRUE);
}
}
return $access_result->cachePerPermissions();
......
......@@ -130,7 +130,7 @@ public function getUrlObject($title_attribute = TRUE) {
$options['attributes']['title'] = $description;
}
if (empty($this->pluginDefinition['url'])) {
return new Url($this->pluginDefinition['route_name'], $this->pluginDefinition['route_parameters'], $options);
return new Url($this->getRouteName(), $this->getRouteParameters(), $options);
}
else {
return Url::fromUri($this->pluginDefinition['url'], $options);
......
......@@ -358,6 +358,11 @@ protected function buildOverviewTreeForm($tree, $delta) {
if (!$link->isEnabled()) {
$form[$id]['title']['#suffix'] = ' (' . $this->t('disabled') . ')';
}
// @todo Remove this in https://www.drupal.org/node/2568785.
elseif ($id === 'menu_plugin_id:user.logout') {
$form[$id]['title']['#suffix'] = ' (' . $this->t('<q>Log in</q> for anonymous users') . ')';
}
// @todo Remove this in https://www.drupal.org/node/2568785.
elseif (($url = $link->getUrlObject()) && $url->isRouted() && $url->getRouteName() == 'user.page') {
$form[$id]['title']['#suffix'] = ' (' . $this->t('logged in users only') . ')';
}
......
......@@ -893,8 +893,7 @@ private function getStandardMenuLink() {
// the front page.
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$result = $menu_link_manager->loadLinksByRoute('user.logout');
$instance = reset($result);
$instance = $menu_link_manager->getInstance(['id' => 'user.logout']);
$this->assertTrue((bool) $instance, 'Standard menu link was loaded');
return $instance;
......
......@@ -89,7 +89,6 @@ function testPageCacheTags() {
'config:block.block.bartik_breadcrumbs',
'config:block.block.bartik_content',
'config:block.block.bartik_tools',
'config:block.block.bartik_login',
'config:block.block.bartik_footer',
'config:block.block.bartik_help',
'config:block.block.bartik_search',
......@@ -106,6 +105,7 @@ function testPageCacheTags() {
'user:0',
'user:' . $author_1->id(),
'config:filter.format.basic_html',
'config:search.settings',
'config:system.menu.account',
'config:system.menu.tools',
'config:system.menu.footer',
......@@ -128,7 +128,6 @@ function testPageCacheTags() {
'config:block.block.bartik_breadcrumbs',
'config:block.block.bartik_content',
'config:block.block.bartik_tools',
'config:block.block.bartik_login',
'config:block.block.bartik_help',
'config:block.block.bartik_search',
'config:block.block.' . $block->id(),
......@@ -144,6 +143,7 @@ function testPageCacheTags() {
'node:' . $node_2->id(),
'user:' . $author_2->id(),
'config:filter.format.full_html',
'config:search.settings',
'config:system.menu.account',
'config:system.menu.tools',
'config:system.menu.footer',
......
......@@ -291,12 +291,13 @@ function testLocaleTranslationSubtreesHashCacheClear() {
$this->assertTrue($original_subtree_hash, 'A valid hash value for the admin menu subtrees was created.');
$this->drupalLogout();
// Translate the string 'Menus' in the xx language. This string appears in
// a link in the admin menu subtrees. Changing the string should create a
// new menu hash if the toolbar subtrees cache is properly cleared.
// Translate the string 'Search and metadata' in the xx language. This
// string appears in a link in the admin menu subtrees. Changing the string
// should create a new menu hash if the toolbar subtrees cache is correctly
// invalidated.
$this->drupalLogin($translate_user);
$search = array(
'string' => 'Menus',
'string' => 'Search and metadata',
'langcode' => $langcode,
'translation' => 'untranslated',
);
......
<?php
/**
* @file
* Contains \Drupal\user\Plugin\Menu\MyAccountMenuLink.
*/
namespace Drupal\user\Plugin\Menu;
use Drupal\Core\Menu\MenuLinkDefault;
use Drupal\Core\Menu\StaticMenuLinkOverridesInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* A menu link that shows "Log in" or "Log out" as appropriate.
*/
class LoginLogoutMenuLink extends MenuLinkDefault {
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* Constructs a new LoginLogoutMenuLink.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Menu\StaticMenuLinkOverridesInterface $static_override
* The static override storage.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, StaticMenuLinkOverridesInterface $static_override, AccountInterface $current_user) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $static_override);
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('menu_link.static.overrides'),
$container->get('current_user')
);
}
/**
* {@inheritdoc}
*/
public function getTitle() {
if ($this->currentUser->isAuthenticated()) {
return $this->t('Log out');
}
else {
return $this->t('Log in');
}
}
/**
* {@inheritdoc}
*/
public function getRouteName() {
if ($this->currentUser->isAuthenticated()) {
return 'user.logout';
}
else {
return 'user.login';
}
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return ['user.roles:authenticated'];
}
}
......@@ -65,11 +65,13 @@ function testSecondaryMenu() {
$this->drupalLogout();
$this->drupalGet('<front>');
// For a logged-out user, expect no secondary links.
$menu = $this->xpath('//ul[@class=:menu_class]', array(
// For a logged-out user, expect the secondary menu to have a "Log in" link.
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', array(
':menu_class' => 'menu',
':href' => 'user/login',
':text' => 'Log in',
));
$this->assertEqual(count($menu), 0, 'The secondary links menu is not rendered, because none of its menu links are accessible for the anonymous user.');
$this->assertEqual(count($link), 1, 'Log in link is in secondary menu.');
}
/**
......
......@@ -4,10 +4,9 @@ user.page:
route_name: user.page
menu_name: account
user.logout:
title: 'Log out'
route_name: user.logout
weight: 10
menu_name: account
class: Drupal\user\Plugin\Menu\LoginLogoutMenuLink
entity.user.collection:
title: People
route_name: entity.user.collection
......
langcode: en
status: true
dependencies:
module:
- user
theme:
- bartik
id: bartik_login
theme: bartik
region: sidebar_first
weight: 0
provider: null
plugin: user_login_block
settings:
id: user_login_block
label: 'User login'
provider: user
label_display: visible
visibility: { }
......@@ -60,6 +60,10 @@ function standard_install() {
));
$shortcut->save();
// Allow all users to use search.
user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, array('search content'));
user_role_grant_permissions(RoleInterface::AUTHENTICATED_ID, array('search content'));
// Enable the admin theme.
\Drupal::configFactory()->getEditable('node.settings')->set('use_admin_theme', TRUE)->save(TRUE);
}
......@@ -73,6 +73,8 @@ protected function setUp() {
$this->accessManager = $this->getMock('\Drupal\Core\Access\AccessManagerInterface');
$this->currentUser = $this->getMock('Drupal\Core\Session\AccountInterface');
$this->currentUser->method('isAuthenticated')
->willReturn(TRUE);
$this->queryFactory = $this->getMockBuilder('Drupal\Core\Entity\Query\QueryFactory')
->disableOriginalConstructor()
->getMock();
......@@ -100,6 +102,7 @@ protected function setUp() {
* - 7
* - 6
* - 8
* - 9
*
* With link 6 being the only external link.
*/
......@@ -113,6 +116,7 @@ protected function mockTree() {
6 => MenuLinkMock::create(array('id' => 'test.example6', 'route_name' => '', 'url' => 'https://www.drupal.org/', 'title' => 'barbar', 'parent' => '')),
7 => MenuLinkMock::create(array('id' => 'test.example7', 'route_name' => 'example7', 'title' => 'bazbaz', 'parent' => '')),
8 => MenuLinkMock::create(array('id' => 'test.example8', 'route_name' => 'example8', 'title' => 'quxqux', 'parent' => '')),
9 => DynamicMenuLinkMock::create(array('id' => 'test.example9', 'parent' => ''))->setCurrentUser($this->currentUser),
);
$this->originalTree = array();
$this->originalTree[1] = new MenuLinkTreeElement($this->links[1], FALSE, 1, FALSE, array());
......@@ -126,6 +130,7 @@ protected function mockTree() {
));
$this->originalTree[6] = new MenuLinkTreeElement($this->links[6], FALSE, 1, FALSE, array());
$this->originalTree[8] = new MenuLinkTreeElement($this->links[8], FALSE, 1, FALSE, array());
$this->originalTree[9] = new MenuLinkTreeElement($this->links[9], FALSE, 1, FALSE, array());
}
/**
......@@ -159,16 +164,17 @@ public function testGenerateIndexAndSort() {
*/
public function testCheckAccess() {
// Those menu links that are non-external will have their access checks
// performed. 8 routes, but 1 is external, 2 already have their 'access'
// property set, and 1 is a child if an inaccessible menu link, so only 4
// performed. 9 routes, but 1 is external, 2 already have their 'access'
// property set, and 1 is a child if an inaccessible menu link, so only 5
// calls will be made.
$this->accessManager->expects($this->exactly(4))
$this->accessManager->expects($this->exactly(5))
->method('checkNamedRoute')
->will($this->returnValueMap(array(
array('example1', array(), $this->currentUser, TRUE, AccessResult::forbidden()),
array('example2', array('foo' => 'bar'), $this->currentUser, TRUE, AccessResult::allowed()->cachePerPermissions()),
array('example3', array('baz' => 'qux'), $this->currentUser, TRUE, AccessResult::neutral()),
array('example5', array(), $this->currentUser, TRUE, AccessResult::allowed()),
array('user.logout', array(), $this->currentUser, TRUE, AccessResult::allowed()),
)));
$this->mockTree();
......@@ -230,7 +236,7 @@ public function testCheckAccess() {
*/
public function testCheckAccessWithLinkToAnyPagePermission() {
$this->mockTree();
$this->currentUser->expects($this->exactly(8))
$this->currentUser->expects($this->exactly(9))
->method('hasPermission')
->with('link to any page')
->willReturn(TRUE);
......@@ -246,6 +252,7 @@ public function testCheckAccessWithLinkToAnyPagePermission() {
$this->assertEquals($expected_access_result, $this->originalTree[5]->subtree[7]->access);
$this->assertEquals($expected_access_result, $this->originalTree[6]->access);
$this->assertEquals($expected_access_result, $this->originalTree[8]->access);
$this->assertEquals($expected_access_result, $this->originalTree[9]->access);
}
/**
......@@ -256,8 +263,8 @@ public function testCheckAccessWithLinkToAnyPagePermission() {
public function testFlatten() {
$this->mockTree();
$tree = $this->defaultMenuTreeManipulators->flatten($this->originalTree);
$this->assertEquals(array(1, 2, 5, 6, 8), array_keys($this->originalTree));
$this->assertEquals(array(1, 2, 5, 6, 8, 3, 4, 7), array_keys($tree));
$this->assertEquals(array(1, 2, 5, 6, 8, 9), array_keys($this->originalTree));
$this->assertEquals(array(1, 2, 5, 6, 8, 9, 3, 4, 7), array_keys($tree));
}
/**
......
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Menu\DynamicMenuLinkMock.
*/
namespace Drupal\Tests\Core\Menu;
use Drupal\Core\Session\AccountInterface;
/**
* Defines a mock implementation of a dynamic menu link used in tests only.
*
* Has a dynamic route and title. This is rather contrived, but there are valid
* use cases.
*
* @see \Drupal\user\Plugin\Menu\LoginLogoutMenuLink
*/
class DynamicMenuLinkMock extends MenuLinkMock {
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* Sets the current user.
*
* Allows the menu link to return the right title and route.
*
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
*
* @return $this
*/
public function setCurrentUser(AccountInterface $current_user) {
$this->currentUser = $current_user;
return $this;
}
/**
* {@inheritdoc}
*/
public function getTitle() {
if ($this->currentUser->isAuthenticated()) {
return 'Log out';
}
else {
return 'Log in';
}
}
/**
* {@inheritdoc}
*/
public function getRouteName() {
if ($this->currentUser->isAuthenticated()) {
return 'user.logout';
}
else {
return 'user.login';
}
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return ['user.roles:authenticated'];
}
}
......@@ -50,7 +50,8 @@ a:active,
.site-branding,
.site-branding__text a,
.site-branding a,
.region-secondary-menu .menu-item a {
.region-secondary-menu .menu-item a,
.region-secondary-menu .menu-item a.is-active {
color: #fffeff;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment