diff --git a/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php b/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php
index e7dcd35..cd6b2c1 100644
--- a/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php
+++ b/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php
@@ -133,25 +133,23 @@ public function build(array $attributes) {
// Copy the path elements for up-casting.
$route_request = $this->getRequestForPath(implode('/', $path_elements), $exclude);
if ($route_request) {
- if (!$route_request->attributes->get('_legacy')) {
- $route_name = $route_request->attributes->get(RouteObjectInterface::ROUTE_NAME);
- // Note that the parameters don't really matter here since we're
- // passing in the request which already has the upcast attributes.
- $parameters = array();
- $access = $this->accessManager->checkNamedRoute($route_name, $parameters, \Drupal::currentUser(), $route_request);
- if ($access) {
- $title = $this->titleResolver->getTitle($route_request, $route_request->attributes->get(RouteObjectInterface::ROUTE_OBJECT));
- }
+ $route_name = $route_request->attributes->get(RouteObjectInterface::ROUTE_NAME);
+ // Note that the parameters don't really matter here since we're
+ // passing in the request which already has the upcast attributes.
+ $parameters = array();
+ $access = $this->accessManager->checkNamedRoute($route_name, $parameters, $this->getCurrentUser(), $route_request);
+ if ($access) {
+ $title = $this->titleResolver->getTitle($route_request, $route_request->attributes->get(RouteObjectInterface::ROUTE_OBJECT));
}
if ($access) {
- if (!$title) {
+ if (!isset($title)) {
// Fallback to using the raw path component as the title if the
// route is missing a _title or _title_callback attribute.
$title = str_replace(array('-', '_'), ' ', Unicode::ucfirst(end($path_elements)));
}
// @todo Replace with a #type => link render element so that the alter
// hook can work with the actual data.
- $links[] = l($title, $route_request->attributes->get('_system_path'));
+ $links[] = $this->l($title, $route_request->attributes->get(RouteObjectInterface::ROUTE_NAME), $route_request->attributes->get('_raw_variables')->all());
}
}
@@ -204,4 +202,13 @@ protected function getRequestForPath($path, array $exclude) {
}
}
+ /**
+ * Gets the current user.
+ *
+ * @return \Drupal\Core\Session\AccountInterface
+ */
+ protected function getCurrentUser() {
+ return \Drupal::currentUser();
+ }
+
}
diff --git a/core/modules/system/tests/Drupal/system/Tests/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php b/core/modules/system/tests/Drupal/system/Tests/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
index bcf0a41..0abdf13 100644
--- a/core/modules/system/tests/Drupal/system/Tests/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
+++ b/core/modules/system/tests/Drupal/system/Tests/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
@@ -7,14 +7,26 @@
namespace Drupal\system\Tests\Breadcrumbs;
+use Drupal\Core\ParamConverter\ParamNotConvertedException;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Core\Utility\LinkGeneratorInterface;
use Drupal\system\PathBasedBreadcrumbBuilder;
use Drupal\Tests\UnitTestCase;
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\HttpFoundation\ParameterBag;
+use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Route;
/**
* Tests machine name controller's transliteration functionality.
*
* @group System
+ * @group Drupal
+ *
+ * @coversDefaultClass \Drupal\system\PathBasedBreadcrumbBuilder
*/
class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
@@ -26,6 +38,20 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
protected $builder;
/**
+ * The title resolver.
+ *
+ * @var \Drupal\Core\Controller\TitleResolverInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $titleResolver;
+
+ /**
+ * The mocked access manager.
+ *
+ * @var \Drupal\Core\Access\AccessManager|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $accessManager;
+
+ /**
* The request matching mock object.
*
* @var \Symfony\Component\Routing\Matcher\RequestMatcherInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -33,6 +59,34 @@ class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
protected $requestMatcher;
/**
+ * The mocked request object.
+ *
+ * @var \Symfony\Component\HttpFoundation\Request|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $request;
+
+ /**
+ * The mocked link generator.
+ *
+ * @var \Drupal\Core\Utility\LinkGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $linkGenerator;
+
+ /**
+ * The current user.
+ *
+ * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $currentUser;
+
+ /**
+ * The mocked path processor.
+ *
+ * @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $pathProcessor;
+
+ /**
* {@inheritdoc}
*/
public static function getInfo() {
@@ -45,47 +99,374 @@ public static function getInfo() {
/**
* {@inheritdoc}
+ *
+ * @covers ::__construct()
*/
public function setUp() {
parent::setUp();
- $this->requestMatcher = $this->getMockBuilder('\Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock();
+ $this->requestMatcher = $this->getMock('\Symfony\Component\Routing\Matcher\RequestMatcherInterface');
- $config_factory = $this->getMockBuilder('\Drupal\Core\Config\ConfigFactoryInterface')->getMock();
- $config_factory->expects($this->any())
- ->method('get')
- ->will($this->returnValue('test'));
+ $config_factory = $this->getConfigFactoryStub(array('system.site' => array('front' => 'test_frontpage')));
- $processor = $this->getMockBuilder('\Drupal\Core\PathProcessor\InboundPathProcessorInterface')->getMock();
- $processor->expects($this->once())
- ->method('processInbound')
- ->will($this->returnValue('test'));
+ $this->pathProcessor = $this->getMock('\Drupal\Core\PathProcessor\InboundPathProcessorInterface');
+ $this->request = $this->getMockBuilder('\Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->getMock();
- $this->builder = new PathBasedBreadcrumbBuilder(
- $this->getMockBuilder('\Symfony\Component\HttpFoundation\Request')->disableOriginalConstructor()->getMock(),
- $this->getMockBuilder('\Drupal\Core\Entity\EntityManagerInterface')->getMock(),
- $this->getMockBuilder('\Drupal\Core\Access\AccessManager')->disableOriginalConstructor()->getMock(),
+ $this->accessManager = $this->getMockBuilder('\Drupal\Core\Access\AccessManager')
+ ->disableOriginalConstructor()->getMock();
+ $this->titleResolver = $this->getMock('\Drupal\Core\Controller\TitleResolverInterface');
+ $this->builder = new TestPathBasedBreadcrumbBuilder(
+ $this->request,
+ $this->getMock('\Drupal\Core\Entity\EntityManagerInterface'),
+ $this->accessManager,
$this->requestMatcher,
- $processor,
+ $this->pathProcessor,
$config_factory,
- $this->getMockBuilder('\Drupal\Core\Controller\TitleResolverInterface')->getMock()
+ $this->titleResolver
);
+
+ $this->builder->setTranslationManager($this->getStringTranslationStub());
+
+ $this->linkGenerator = $this->getMock('Drupal\Core\Utility\LinkGeneratorInterface');
+ $this->builder->setLinkGenerator($this->linkGenerator);
+
+ $this->currentUser = $this->getMock('Drupal\Core\Session\AccountInterface');
+ $this->builder->setCurrentUser($this->currentUser);
+ }
+
+ /**
+ * Tests the build method on the frontpage.
+ *
+ * @covers ::build()
+ */
+ public function testBuildOnFrontpage() {
+ $this->request->expects($this->once())
+ ->method('getPathInfo')
+ ->will($this->returnValue('/'));
+
+ $links = $this->builder->build(array());
+ $this->assertEquals(array(), $links);
+ }
+
+ /**
+ * Tests the build method with one path element.
+ *
+ * @covers ::build()
+ */
+ public function testBuildWithOnePathElement() {
+ $this->request->expects($this->once())
+ ->method('getPathInfo')
+ ->will($this->returnValue('/example'));
+
+ $this->setupLinkGeneratorWithFrontpage();
+
+ $links = $this->builder->build(array());
+ $this->assertEquals(array(0 => 'Home'), $links);
+ }
+
+ /**
+ * Tests the build method with two path elements.
+ *
+ * @covers ::build()
+ * @covers ::getRequestForPath()
+ */
+ public function testBuildWithTwoPathElements() {
+ $this->request->expects($this->once())
+ ->method('getPathInfo')
+ ->will($this->returnValue('/example/baz'));
+ $this->setupStubPathProcessor();
+
+ $route_1 = new Route('/example');
+
+ $this->requestMatcher->expects($this->exactly(1))
+ ->method('matchRequest')
+ ->will($this->returnCallback(function(Request $request) use ($route_1) {
+ if ($request->getPathInfo() == '/example') {
+ return array(
+ RouteObjectInterface::ROUTE_NAME => 'example',
+ RouteObjectInterface::ROUTE_OBJECT => $route_1,
+ '_raw_variables' => new ParameterBag(array()),
+ );
+ }
+ }));
+
+ $link_example = 'Example';
+ $link_front = 'Home';
+ $this->linkGenerator->expects($this->at(0))
+ ->method('generate')
+ ->with('Example', 'example', array(), array())
+ ->will($this->returnValue($link_example));
+ $this->linkGenerator->expects($this->at(1))
+ ->method('generate')
+ ->with('Home', '', array(), array())
+ ->will($this->returnValue($link_front));
+ $this->setupAccessManagerWithTrue();
+
+ $links = $this->builder->build(array());
+ $this->assertEquals(array(0 => 'Home', 1 => $link_example), $links);
+ }
+
+ /**
+ * Tests the build method with three path elements.
+ *
+ * @covers ::build()
+ * @covers ::getRequestForPath()
+ */
+ public function testBuildWithThreePathElements() {
+ $this->request->expects($this->once())
+ ->method('getPathInfo')
+ ->will($this->returnValue('/example/bar/baz'));
+ $this->setupStubPathProcessor();
+
+ $route_1 = new Route('/example/bar');
+ $route_2 = new Route('/example');
+
+ $this->requestMatcher->expects($this->exactly(2))
+ ->method('matchRequest')
+ ->will($this->returnCallback(function(Request $request) use ($route_1, $route_2) {
+ if ($request->getPathInfo() == '/example/bar') {
+ return array(
+ RouteObjectInterface::ROUTE_NAME => 'example_bar',
+ RouteObjectInterface::ROUTE_OBJECT => $route_1,
+ '_raw_variables' => new ParameterBag(array()),
+ );
+ }
+ elseif ($request->getPathInfo() == '/example') {
+ return array(
+ RouteObjectInterface::ROUTE_NAME => 'example',
+ RouteObjectInterface::ROUTE_OBJECT => $route_2,
+ '_raw_variables' => new ParameterBag(array()),
+ );
+ }
+ }));
+
+ $link_example_bar = 'Bar';
+ $link_example = 'Example';
+ $link_front = 'Home';
+ $this->linkGenerator->expects($this->at(0))
+ ->method('generate')
+ ->with('Bar', 'example_bar', array(), array())
+ ->will($this->returnValue($link_example_bar));
+
+ $this->linkGenerator->expects($this->at(1))
+ ->method('generate')
+ ->with('Example', 'example', array(), array())
+ ->will($this->returnValue($link_example));
+ $this->linkGenerator->expects($this->at(2))
+ ->method('generate')
+ ->with('Home', '', array(), array())
+ ->will($this->returnValue($link_front));
+ $this->setupAccessManagerWithTrue();
+
+ $links = $this->builder->build(array());
+ $this->assertEquals(array(0 => 'Home', 1 => $link_example, 2 => $link_example_bar), $links);
}
/**
* Tests that MethodNotAllowedExceptions are caught.
+ *
+ * @covers ::build()
+ * @covers ::getRequestForPath()
*/
- public function testPathMatchingExceptions() {
+ public function testBuildWithPathMatchingExceptions() {
+ $this->request->expects($this->once())
+ ->method('getPathInfo')
+ ->will($this->returnValue('/example/bar'));
+ $this->setupStubPathProcessor();
+
$this->requestMatcher->expects($this->any())
->method('matchRequest')
->will($this->throwException(new MethodNotAllowedException(array())));
+ $this->setupLinkGeneratorWithFrontpage();
+
+ $links = $this->builder->build(array());
+
+ // No path matched, though at least the frontpage is displayed.
+ $this->assertEquals(array(0 => 'Home'), $links);
+ }
+
+ /**
+ * Tests that ParamNotConvertedException are caught.
+ *
+ * @covers ::build()
+ * @covers ::getRequestForPath()
+ */
+ public function testBuildWithParamNotConvertedException() {
+ $this->request->expects($this->once())
+ ->method('getPathInfo')
+ ->will($this->returnValue('/example/bar'));
+ $this->setupStubPathProcessor();
+
+ $this->requestMatcher->expects($this->any())
+ ->method('matchRequest')
+ ->will($this->throwException(new ParamNotConvertedException()));
+ $this->setupLinkGeneratorWithFrontpage();
+
+ $links = $this->builder->build(array());
+
+ // No path matched, though at least the frontpage is displayed.
+ $this->assertEquals(array(0 => 'Home'), $links);
+ }
+
+ /**
+ * Tests the build method with a non processed path.
+ *
+ * @covers ::build()
+ * @covers ::getRequestForPath()
+ */
+ public function testBuildWithNonProcessedPath() {
+ $this->request->expects($this->once())
+ ->method('getPathInfo')
+ ->will($this->returnValue('/example/bar'));
+
+ $this->pathProcessor->expects($this->once())
+ ->method('processInbound')
+ ->will($this->returnValue(FALSE));
+
+ $this->requestMatcher->expects($this->any())
+ ->method('matchRequest')
+ ->will($this->returnValue(array()));
+ $this->setupLinkGeneratorWithFrontpage();
+
+ $links = $this->builder->build(array());
- // Test the protected method of the class by making it accessible with
- // reflection.
- $method = new \ReflectionMethod('\Drupal\system\PathBasedBreadcrumbBuilder', 'getRequestForPath');
- $method->setAccessible(true);
+ // No path matched, though at least the frontpage is displayed.
+ $this->assertEquals(array(0 => 'Home'), $links);
+ }
+
+
+ /**
+ * Tests that ResourceNotFoundException are caught.
+ *
+ * @covers ::build()
+ * @covers ::getRequestForPath()
+ */
+ public function testBuildWithRosourceNotFoundException() {
+ $this->request->expects($this->once())
+ ->method('getPathInfo')
+ ->will($this->returnValue('/example/bar'));
+ $this->setupStubPathProcessor();
+
+ $this->requestMatcher->expects($this->any())
+ ->method('matchRequest')
+ ->will($this->throwException(new ResourceNotFoundException()));
+ $this->setupLinkGeneratorWithFrontpage();
- $method->invoke($this->builder, 'test', array());
+ $links = $this->builder->build(array());
+
+ // No path matched, though at least the frontpage is displayed.
+ $this->assertEquals(array(0 => 'Home'), $links);
+ }
+
+ /**
+ * Tests the applied method.
+ *
+ * @covers ::applies()
+ */
+ public function testApplies() {
+ $this->assertTrue($this->builder->applies(array()));
+ }
+
+ /**
+ * Tests the breadcrumb for an user path.
+ *
+ * @covers ::build()
+ * @covers ::getRequestForPath()
+ */
+ public function testBuildWithUserPath() {
+ $this->request->expects($this->once())
+ ->method('getPathInfo')
+ ->will($this->returnValue('/user/1/edit'));
+ $this->setupStubPathProcessor();
+
+ $route_1 = new Route('/user/1');
+
+ $this->requestMatcher->expects($this->exactly(1))
+ ->method('matchRequest')
+ ->will($this->returnCallback(function(Request $request) use ($route_1) {
+ if ($request->getPathInfo() == '/user/1') {
+ return array(
+ RouteObjectInterface::ROUTE_NAME => 'user_page',
+ RouteObjectInterface::ROUTE_OBJECT => $route_1,
+ '_raw_variables' => new ParameterBag(array()),
+ );
+ }
+ }));
+
+ $link_user = 'Admin';
+ $link_front = 'Home';
+ $this->linkGenerator->expects($this->at(0))
+ ->method('generate')
+ ->with('Admin', 'user_page', array(), array())
+ ->will($this->returnValue($link_user));
+
+ $this->linkGenerator->expects($this->at(1))
+ ->method('generate')
+ ->with('Home', '', array(), array())
+ ->will($this->returnValue($link_front));
+ $this->setupAccessManagerWithTrue();
+ $this->titleResolver->expects($this->once())
+ ->method('getTitle')
+ ->with($this->anything(), $route_1)
+ ->will($this->returnValue('Admin'));
+
+ $links = $this->builder->build(array());
+ $this->assertEquals(array(0 => 'Home', 1 => $link_user), $links);
+ }
+
+ /**
+ * Setup the link generator with a frontpage route.
+ */
+ public function setupLinkGeneratorWithFrontpage() {
+ $this->linkGenerator->expects($this->once())
+ ->method('generate')
+ ->with($this->anything(), '', array())
+ ->will($this->returnCallback(function($title) {
+ return '' . $title . '';
+ }));
+ }
+
+ /**
+ * Setup the access manager to always return TRUE.
+ */
+ public function setupAccessManagerWithTrue() {
+ $this->accessManager->expects($this->any())
+ ->method('checkNamedRoute')
+ ->will($this->returnValue(TRUE));
+ }
+
+ protected function setupStubPathProcessor() {
+ $this->pathProcessor->expects($this->any())
+ ->method('processInbound')
+ ->will($this->returnArgument(0));
}
}
+
+class TestPathBasedBreadcrumbBuilder extends PathBasedBreadcrumbBuilder {
+
+ /**
+ * The current user.
+ *
+ * @var \Drupal\Core\Session\AccountInterface
+ */
+ protected $currentUser;
+
+ public function setTranslationManager(TranslationInterface $translation_manager) {
+ $this->translationManager = $translation_manager;
+ }
+
+ public function setLinkGenerator(LinkGeneratorInterface $link_generator) {
+ $this->linkGenerator = $link_generator;
+ }
+
+ public function setCurrentUser(AccountInterface $current_user) {
+ $this->currentUser = $current_user;
+ }
+
+ protected function getCurrentUser() {
+ return $this->currentUser;
+ }
+
+}
+