diff --git a/core/core.services.yml b/core/core.services.yml index c43da8c..1c926c2 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -664,7 +664,7 @@ services: class: Drupal\Core\Access\AccessArgumentsResolver access_manager: class: Drupal\Core\Access\AccessManager - arguments: ['@router.route_provider', '@url_generator', '@paramconverter_manager', '@access_arguments_resolver', '@request_stack'] + arguments: ['@router.route_provider', '@url_generator', '@paramconverter_manager', '@access_arguments_resolver', '@request_stack', '@current_user'] calls: - [setContainer, ['@service_container']] access_route_subscriber: diff --git a/core/includes/common.inc b/core/includes/common.inc index 618c23b..eeee7cb 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -2809,6 +2809,14 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) { $current->postRenderCache = NestedArray::mergeDeep($current->postRenderCache, $parent->postRenderCache); $stack->push($current); }; + /** @var \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver */ + $controller_resolver = \Drupal::service('controller_resolver'); + if (!isset($elements['#access']) && isset($elements['#access_callback'])) { + if (is_string($elements['#access_callback']) && strpos($elements['#access_callback'], '::') === FALSE) { + $elements['#access_callback'] = $controller_resolver->getControllerFromDefinition($elements['#access_callback']); + } + $elements['#access'] = call_user_func($elements['#access_callback'], $elements); + } // Early-return nothing if user does not have access. if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) { @@ -2856,8 +2864,6 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) { // Make any final changes to the element before it is rendered. This means // that the $element or the children can be altered or corrected before the // element is rendered into the final text. - /** @var \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver */ - $controller_resolver = \Drupal::service('controller_resolver'); if (isset($elements['#pre_render'])) { foreach ($elements['#pre_render'] as $callable) { if (is_string($callable) && strpos($callable, '::') === FALSE) { diff --git a/core/lib/Drupal/Core/Access/AccessManager.php b/core/lib/Drupal/Core/Access/AccessManager.php index 54d13de..8a8af77 100644 --- a/core/lib/Drupal/Core/Access/AccessManager.php +++ b/core/lib/Drupal/Core/Access/AccessManager.php @@ -103,6 +103,13 @@ class AccessManager implements ContainerAwareInterface, AccessManagerInterface { protected $requestStack; /** + * The current user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $currentUser; + + /** * Constructs a AccessManager instance. * * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider @@ -115,13 +122,16 @@ class AccessManager implements ContainerAwareInterface, AccessManagerInterface { * The access arguments resolver. * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack * The request stack object. + * @param \Drupal\Core\Session\AccountInterface $current_user + * The current user. */ - public function __construct(RouteProviderInterface $route_provider, UrlGeneratorInterface $url_generator, ParamConverterManagerInterface $paramconverter_manager, AccessArgumentsResolverInterface $arguments_resolver, RequestStack $requestStack) { + public function __construct(RouteProviderInterface $route_provider, UrlGeneratorInterface $url_generator, ParamConverterManagerInterface $paramconverter_manager, AccessArgumentsResolverInterface $arguments_resolver, RequestStack $requestStack, AccountInterface $current_user) { $this->routeProvider = $route_provider; $this->urlGenerator = $url_generator; $this->paramConverterManager = $paramconverter_manager; $this->argumentsResolver = $arguments_resolver; $this->requestStack = $requestStack; + $this->currentUser = $current_user; } /** @@ -182,7 +192,7 @@ protected function applies(Route $route) { /** * {@inheritdoc} */ - public function checkNamedRoute($route_name, array $parameters = array(), AccountInterface $account, Request $route_request = NULL) { + public function checkNamedRoute($route_name, array $parameters = array(), AccountInterface $account = NULL, Request $route_request = NULL) { try { $route = $this->routeProvider->getRouteByName($route_name, $parameters); if (empty($route_request)) { @@ -210,7 +220,10 @@ public function checkNamedRoute($route_name, array $parameters = array(), Accoun /** * {@inheritdoc} */ - public function check(Route $route, Request $request, AccountInterface $account) { + public function check(Route $route, Request $request, AccountInterface $account = NULL) { + if (!isset($account)) { + $account = $this->currentUser; + } $checks = $route->getOption('_access_checks') ?: array(); $conjunction = $route->getOption('_access_mode') ?: static::ACCESS_MODE_ALL; diff --git a/core/lib/Drupal/Core/Access/AccessManagerInterface.php b/core/lib/Drupal/Core/Access/AccessManagerInterface.php index df88ba6..db6cfa3 100644 --- a/core/lib/Drupal/Core/Access/AccessManagerInterface.php +++ b/core/lib/Drupal/Core/Access/AccessManagerInterface.php @@ -45,7 +45,8 @@ * @param array $parameters * Optional array of values to substitute into the route path patern. * @param \Drupal\Core\Session\AccountInterface $account - * The current user. + * (optional) Run access checks for this account. Defaults to the current + * user. * @param \Symfony\Component\HttpFoundation\Request $route_request * Optional incoming request object. If not provided, one will be built * using the route information and the current request from the container. @@ -53,7 +54,7 @@ * @return bool * Returns TRUE if the user has access to the route, otherwise FALSE. */ - public function checkNamedRoute($route_name, array $parameters = array(), AccountInterface $account, Request $route_request = NULL); + public function checkNamedRoute($route_name, array $parameters = array(), AccountInterface $account = NULL, Request $route_request = NULL); /** * For each route, saves a list of applicable access checks to the route. @@ -86,11 +87,12 @@ public function addCheckService($service_id, $service_method, array $applies_che * @param \Symfony\Component\HttpFoundation\Request $request * The incoming request object. * @param \Drupal\Core\Session\AccountInterface $account - * The current account. + * (optional) Run access checks for this account. Defaults to the current + * user. * * @return bool * Returns TRUE if the user has access to the route, otherwise FALSE. */ - public function check(Route $route, Request $request, AccountInterface $account); + public function check(Route $route, Request $request, AccountInterface $account = NULL); } diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php index ea407cc..d97f017 100644 --- a/core/lib/Drupal/Core/Url.php +++ b/core/lib/Drupal/Core/Url.php @@ -10,6 +10,7 @@ use Drupal\Component\Utility\UrlHelper; use Drupal\Core\DependencyInjection\DependencySerializationTrait; use Drupal\Core\Routing\UrlGeneratorInterface; +use Drupal\Core\Session\AccountInterface; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; @@ -27,6 +28,13 @@ class Url { protected $urlGenerator; /** + * The access manager + * + * @var \Drupal\Core\Access\AccessManagerInterface + */ + protected $accessManager; + + /** * The route name. * * @var string @@ -386,6 +394,7 @@ public function toRenderArray() { '#route_name' => $this->getRouteName(), '#route_parameters' => $this->getRouteParameters(), '#options' => $this->getOptions(), + '#access_callback' => array(get_class(), 'renderAccess'), ); } } @@ -412,6 +421,45 @@ public function getInternalPath() { } /** + * Checks this Url object against applicable access check services. + * + * Determines whether the route is accessible or not. + * + * @param \Drupal\Core\Session\AccountInterface $account + * (optional) Run access checks for this account. Defaults to the current + * user. + * + * @return bool + * Returns TRUE if the user has access to the url, otherwise FALSE. + */ + public function access(AccountInterface $account = NULL) { + return $this->accessManager()->checkNamedRoute($this->getRouteName(), $this->getRouteParameters(), $account); + } + + /** + * Checks a Url render element against applicable access check services. + * + * @param array $element + * A render element as returned from \Drupal\Core\Url::toRenderArray(). + * + * @return bool + * Returns TRUE if the current user has access to the url, otherwise FALSE. + */ + public static function renderAccess(array $element) { + return (new static($element['#route_name'], $element['#route_parameters'], $element['#options']))->access(); + } + + /** + * @return \Drupal\Core\Access\AccessManagerInterface + */ + protected function accessManager() { + if (!isset($this->accessManager)) { + $this->accessManager = \Drupal::service('access_manager'); + } + return $this->accessManager; + } + + /** * Gets the URL generator. * * @return \Drupal\Core\Routing\UrlGeneratorInterface diff --git a/core/modules/rdf/src/Tests/Field/TaxonomyTermReferenceRdfaTest.php b/core/modules/rdf/src/Tests/Field/TaxonomyTermReferenceRdfaTest.php index ed4bbf5..b3610d3 100644 --- a/core/modules/rdf/src/Tests/Field/TaxonomyTermReferenceRdfaTest.php +++ b/core/modules/rdf/src/Tests/Field/TaxonomyTermReferenceRdfaTest.php @@ -7,9 +7,8 @@ namespace Drupal\rdf\Tests\Field; use Drupal\Core\Field\FieldStorageDefinitionInterface; -use Drupal\rdf\Tests\Field\FieldRdfaTestBase; -use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Language\LanguageInterface; +use Drupal\user\Entity\Role; /** * Tests the RDFa output of the taxonomy term reference field formatter. @@ -100,6 +99,10 @@ protected function setUp() { public function testAllFormatters() { // Tests the plain formatter. $this->assertFormatterRdfa(array('type' => 'taxonomy_term_reference_plain'), 'http://schema.org/about', array('value' => $this->term->getName(), 'type' => 'literal')); + // Grant the access content permission to the anonymous user. + Role::create(array('id' => DRUPAL_ANONYMOUS_RID)) + ->grantPermission('access content') + ->save(); // Tests the link formatter. $term_uri = $this->getAbsoluteUri($this->term); $this->assertFormatterRdfa(array('type'=>'taxonomy_term_reference_link'), 'http://schema.org/about', array('value' => $term_uri, 'type' => 'uri')); diff --git a/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php b/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php index 77e63e1..7740c79 100644 --- a/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php +++ b/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php @@ -12,9 +12,8 @@ use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; -use Drupal\Core\Routing\UrlGeneratorInterface; -use Drupal\Core\Session\AccountInterface; use Drupal\Component\Utility\Xss; +use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -28,13 +27,6 @@ class SystemBrandingBlock extends BlockBase implements ContainerFactoryPluginInterface { /** - * The URL generator. - * - * @var \Drupal\Core\Routing\UrlGeneratorInterface - */ - protected $urlGenerator; - - /** * Stores the configuration factory. * * @var \Drupal\Core\Config\ConfigFactoryInterface @@ -42,13 +34,6 @@ class SystemBrandingBlock extends BlockBase implements ContainerFactoryPluginInt protected $configFactory; /** - * The current user. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $currentUser; - - /** * Creates a SystemBrandingBlock instance. * * @param array $configuration @@ -59,16 +44,10 @@ class SystemBrandingBlock extends BlockBase implements ContainerFactoryPluginInt * The plugin implementation definition. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The factory for configuration objects. - * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator - * The url generator service. - * @param \Drupal\Core\Session\AccountInterface $current_user - * The current user. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory, UrlGeneratorInterface $url_generator, AccountInterface $current_user) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->configFactory = $config_factory; - $this->urlGenerator = $url_generator; - $this->currentUser = $current_user; } /** @@ -79,9 +58,7 @@ public static function create(ContainerInterface $container, array $configuratio $configuration, $plugin_id, $plugin_definition, - $container->get('config.factory'), - $container->get('url_generator'), - $container->get('current_user') + $container->get('config.factory') ); } @@ -111,26 +88,26 @@ public function blockForm($form, FormStateInterface $form_state) { $theme = $form_state['block_theme']; // Get permissions. - $administer_themes_access = $this->currentUser->hasPermission('administer themes'); - $administer_site_configuration_access = $this->currentUser->hasPermission('administer site configuration'); - - if ($administer_themes_access) { - // Get paths to theme settings pages. - $appearance_settings_url = $this->urlGenerator->generateFromRoute('system.theme_settings'); - $theme_settings_url = $this->urlGenerator->generateFromRoute('system.theme_settings_theme', array('theme' => $theme)); + $url_system_theme_settings = new Url('system.theme_settings'); + $url_system_theme_settings_theme = new Url('system.theme_settings_theme', array('theme' => $theme)); + if ($url_system_theme_settings->access() && $url_system_theme_settings_theme->access()) { // Provide links to the Appearance Settings and Theme Settings pages // if the user has access to administer themes. - $site_logo_description = $this->t('Defined on the Appearance Settings or Theme Settings page.', array('@appearance' => $appearance_settings_url, '@theme' => $theme_settings_url)); + $site_logo_description = $this->t('Defined on the Appearance Settings or Theme Settings page.', array( + '@appearance' => $url_system_theme_settings->toString(), + '@theme' => $url_system_theme_settings_theme->toString(), + )); } else { // Explain that the user does not have access to the Appearance and Theme // Settings pages. $site_logo_description = $this->t('Defined on the Appearance or Theme Settings page. You do not have the appropriate permissions to change the site logo.'); } - if ($administer_site_configuration_access) { + $url_system_site_information_settings = new Url('system.site_information_settings'); + if ($url_system_site_information_settings->access()) { // Get paths to settings pages. - $site_information_url = $this->urlGenerator->generateFromRoute('system.site_information_settings'); + $site_information_url = $url_system_site_information_settings->toString(); // Provide link to Site Information page if the user has access to // administer site configuration. diff --git a/core/modules/system/src/Tests/Common/RenderTest.php b/core/modules/system/src/Tests/Common/RenderTest.php index 0789052..57f8c08 100644 --- a/core/modules/system/src/Tests/Common/RenderTest.php +++ b/core/modules/system/src/Tests/Common/RenderTest.php @@ -54,6 +54,31 @@ function testDrupalRenderBasics() { 'expected' => '', ), array( + 'name' => 'access denied via callback', + 'value' => array( + '#markup' => 'foo', + '#access_callback' => 'is_bool', + ), + 'expected' => '', + ), + array( + 'name' => 'access granted via callback', + 'value' => array( + '#markup' => 'foo', + '#access_callback' => 'is_array', + ), + 'expected' => 'foo', + ), + array( + 'name' => 'access FALSE is honored', + 'value' => array( + '#markup' => 'foo', + '#access' => FALSE, + '#access_callback' => 'is_array', + ), + 'expected' => '', + ), + array( 'name' => 'previously printed', 'value' => array( '#markup' => 'foo', diff --git a/core/modules/system/src/Tests/Form/ConfirmFormTest.php b/core/modules/system/src/Tests/Form/ConfirmFormTest.php index 3ea2820..fcb4e61 100644 --- a/core/modules/system/src/Tests/Form/ConfirmFormTest.php +++ b/core/modules/system/src/Tests/Form/ConfirmFormTest.php @@ -33,7 +33,7 @@ function testConfirmForm() { // Test canelling the form. $this->clickLink(t('ConfirmFormTestForm::getCancelText().')); - $this->assertUrl('admin', array(), "The form's cancel link was followed."); + $this->assertUrl('form-test/autocomplete', array(), "The form's cancel link was followed."); // Test submitting the form. $this->drupalPostForm('form-test/confirm-form', NULL, t('ConfirmFormTestForm::getConfirmText().')); @@ -47,7 +47,7 @@ function testConfirmForm() { // Test cancelling the form with a complex destination. $this->drupalGet('form-test/confirm-form-array-path'); $this->clickLink(t('ConfirmFormArrayPathTestForm::getCancelText().')); - $this->assertUrl('admin', array('query' => array('destination' => 'admin/config')), "The form's complex cancel link was followed."); + $this->assertUrl('form-test/confirm-form', array('query' => array('destination' => 'admin/config')), "The form's complex cancel link was followed."); } } diff --git a/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php b/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php new file mode 100644 index 0000000..66239c9 --- /dev/null +++ b/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php @@ -0,0 +1,68 @@ +installSchema('system', ['router']); + } + + /** + * Ensures that the access() method on \Drupal\Core\Url objects works. + */ + public function testAccess() { + \Drupal::service('router.builder')->rebuild(); + /** @var \Drupal\user\RoleInterface $role_with_access */ + $role_with_access = Role::create(['id' => 'role_with_access']); + $role_with_access->grantPermission('administer users'); + $role_with_access->save(); + + /** @var \Drupal\user\RoleInterface $role_without_access */ + $role_without_access = Role::create(['id' => 'role_without_access']); + $role_without_access->save(); + + $user_with_access = User::create(['roles' => ['role_with_access']]); + $user_without_access = User::create(['roles' => ['role_without_access']]); + + $url_always_access = new Url('router_test.1'); + $this->assertTrue($url_always_access->access($user_with_access)); + $this->assertTrue($url_always_access->access($user_without_access)); + + $url_none_access = new Url('router_test.15'); + $this->assertFalse($url_none_access->access($user_with_access)); + $this->assertFalse($url_none_access->access($user_without_access)); + + $url_access = new Url('router_test.16'); + $this->assertTrue($url_access->access($user_with_access)); + $this->assertFalse($url_access->access($user_without_access)); + } + +} diff --git a/core/modules/system/tests/modules/form_test/src/ConfirmFormArrayPathTestForm.php b/core/modules/system/tests/modules/form_test/src/ConfirmFormArrayPathTestForm.php index c089a26..6cd8c2f 100644 --- a/core/modules/system/tests/modules/form_test/src/ConfirmFormArrayPathTestForm.php +++ b/core/modules/system/tests/modules/form_test/src/ConfirmFormArrayPathTestForm.php @@ -25,7 +25,7 @@ public function getFormId() { * {@inheritdoc} */ public function getCancelUrl() { - return new Url('system.admin', array(), array( + return new Url('form_test.route6', array(), array( 'query' => array( 'destination' => 'admin/config', ), diff --git a/core/modules/system/tests/modules/form_test/src/ConfirmFormTestForm.php b/core/modules/system/tests/modules/form_test/src/ConfirmFormTestForm.php index a031747..fd74f3b 100644 --- a/core/modules/system/tests/modules/form_test/src/ConfirmFormTestForm.php +++ b/core/modules/system/tests/modules/form_test/src/ConfirmFormTestForm.php @@ -34,7 +34,7 @@ public function getQuestion() { * {@inheritdoc} */ public function getCancelUrl() { - return new Url('system.admin'); + return new Url('form_test.route8'); } /** diff --git a/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml b/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml index 7405d88..5b02a3b 100644 --- a/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml +++ b/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml @@ -93,6 +93,20 @@ router_test.14: defaults: _controller: '\Drupal\router_test\TestControllers::test9' +router_test.15: + path: '/router_test/test15' + defaults: + _controller: '\Drupal\router_test\TestControllers::test1' + requirements: + _access: 'FALSE' + +router_test.16: + path: '/router_test/test16' + defaults: + _controller: '\Drupal\router_test\TestControllers::test1' + requirements: + _permission: 'administer users' + router_test.hierarchy_parent: path: '/menu-test/parent' defaults: diff --git a/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php b/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php index 3aa8046..0f45b83 100644 --- a/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php @@ -92,6 +92,11 @@ class AccessManagerTest extends UnitTestCase { protected $requestStack; /** + * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $currentUser; + + /** * {@inheritdoc} */ protected function setUp() { @@ -129,11 +134,12 @@ protected function setUp() { $this->paramConverter = $this->getMock('Drupal\Core\ParamConverter\ParamConverterManagerInterface'); $this->account = $this->getMock('Drupal\Core\Session\AccountInterface'); + $this->currentUser = $this->getMock('Drupal\Core\Session\AccountInterface'); $this->argumentsResolver = $this->getMock('Drupal\Core\Access\AccessArgumentsResolverInterface'); $this->requestStack = new RequestStack(); - $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack); + $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack, $this->currentUser); $this->accessManager->setContainer($this->container); } @@ -162,7 +168,7 @@ public function testSetChecks() { */ public function testSetChecksWithDynamicAccessChecker() { // Setup the access manager. - $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack); + $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack, $this->currentUser); $this->accessManager->setContainer($this->container); // Setup the dynamic access checker. @@ -220,6 +226,25 @@ public function testCheck() { } /** + * Tests \Drupal\Core\Access\AccessManager::check() with no account specified. + * + * @covers ::check + */ + public function testCheckWithNullAccount() { + $this->setupAccessChecker(); + $this->accessManager->setChecks($this->routeCollection); + $request = new Request; + $route = $this->routeCollection->get('test_route_2'); + $this->argumentsResolver->expects($this->once()) + ->method('getArguments') + ->with(array($this->container->get('test_access_default'), 'access'), $route, $request, $this->currentUser) + ->will($this->returnCallback(function ($callable, $route, $request, $account) { + return array($route); + })); + $this->accessManager->check($route, $request); + } + + /** * Provides data for the conjunction test. * * @return array @@ -472,7 +497,7 @@ public function testCheckNamedRouteWithUpcastedValues() { $subrequest = Request::create('/test-route-1/example'); - $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack); + $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack, $this->currentUser); $this->accessManager->setContainer($this->container); $this->requestStack->push(new Request()); @@ -532,7 +557,7 @@ public function testCheckNamedRouteWithDefaultValue() { $subrequest = Request::create('/test-route-1/example'); - $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack); + $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack, $this->currentUser); $this->accessManager->setContainer($this->container); $this->requestStack->push(new Request()); @@ -610,7 +635,7 @@ public function testCheckException($return_value, $access_mode) { ->will($this->returnValue($return_value)); $container->set('test_incorrect_value', $access_check); - $access_manager = new AccessManager($route_provider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack); + $access_manager = new AccessManager($route_provider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack, $this->currentUser); $access_manager->setContainer($container); $access_manager->addCheckService('test_incorrect_value', 'access'); @@ -665,7 +690,7 @@ protected static function convertAccessCheckInterfaceToString($constant) { * Adds a default access check service to the container and the access manager. */ protected function setupAccessChecker() { - $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack); + $this->accessManager = new AccessManager($this->routeProvider, $this->urlGenerator, $this->paramConverter, $this->argumentsResolver, $this->requestStack, $this->currentUser); $this->accessManager->setContainer($this->container); $access_check = new DefaultAccessCheck(); $this->container->register('test_access_default', $access_check); diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php index 92f429d..32a75c0 100644 --- a/core/tests/Drupal/Tests/Core/UrlTest.php +++ b/core/tests/Drupal/Tests/Core/UrlTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\Core; +use Drupal\Core\Access\AccessManagerInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\Url; use Drupal\Tests\UnitTestCase; @@ -22,6 +23,11 @@ class UrlTest extends UnitTestCase { /** + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + protected $container; + + /** * The URL generator * * @var \Drupal\Core\Routing\UrlGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject @@ -60,10 +66,10 @@ protected function setUp() { ->will($this->returnValueMap($this->map)); $this->router = $this->getMock('Drupal\Tests\Core\Routing\TestRouterInterface'); - $container = new ContainerBuilder(); - $container->set('router.no_access_checks', $this->router); - $container->set('url_generator', $this->urlGenerator); - \Drupal::setContainer($container); + $this->container = new ContainerBuilder(); + $this->container->set('router.no_access_checks', $this->router); + $this->container->set('url_generator', $this->urlGenerator); + \Drupal::setContainer($this->container); } /** @@ -318,4 +324,81 @@ public function testGetOptions($urls) { } } + /** + * Tests the access() method. + * + * @param bool $access + * + * @covers ::access + * @covers ::getAccessManager + * @covers ::setAccessManager + * @dataProvider accessProvider + */ + public function testAccess($access) { + $account = $this->getMock('Drupal\Core\Session\AccountInterface'); + $url = new TestUrl('entity.node.canonical', ['node' => 3]); + $url->setAccessManager($this->getMockAccessManager($access, $account)); + $this->assertEquals($access, $url->access($account)); + } + + /** + * Tests the renderAccess() method. + * + * @param bool $access + * + * @covers ::renderAccess + * @dataProvider accessProvider + */ + public function testRenderAccess($access) { + $element = array( + '#route_name' => 'entity.node.canonical', + '#route_parameters' => ['node' => 3], + '#options' => [], + ); + $this->container->set('current_user', $this->getMock('Drupal\Core\Session\AccountInterface')); + $this->container->set('access_manager', $this->getMockAccessManager($access)); + $this->assertEquals($access, TestUrl::renderAccess($element)); + } + + /** + * Creates a mock access manager for the access tests. + * + * @param bool $access + * @param \Drupal\Core\Session\AccountInterface|NULL $account + * + * @return \Drupal\Core\Access\AccessManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getMockAccessManager($access, $account = NULL) { + $access_manager = $this->getMock('Drupal\Core\Access\AccessManagerInterface'); + $access_manager->expects($this->once()) + ->method('checkNamedRoute') + ->with('entity.node.canonical', ['node' => 3], $account) + ->willReturn($access); + return $access_manager; + } + + /** + * Data provider for the access test methods. + */ + public function accessProvider() { + return array( + array(TRUE), + array(FALSE), + ); + } + +} + +class TestUrl extends Url { + + /** + * Sets the access manager. + * + * @param \Drupal\Core\Access\AccessManagerInterface $access_manager + */ + public function setAccessManager(AccessManagerInterface $access_manager) { + $this->accessManager = $access_manager; + } + + }