Commit 58f31ac2 authored by alexpott's avatar alexpott

Issue #2209997 by Mile23, larowlan, YesCT: Split ForumBreadcrumbBuilder in two.

parent 2e7b2098
......@@ -2,8 +2,13 @@ services:
forum_manager:
class: Drupal\forum\ForumManager
arguments: ['@config.factory', '@entity.manager', '@database', '@field.info', '@string_translation']
forum.breadcrumb:
class: Drupal\forum\ForumBreadcrumbBuilder
forum.breadcrumb.node:
class: Drupal\forum\Breadcrumb\ForumNodeBreadcrumbBuilder
arguments: ['@entity.manager', '@config.factory', '@forum_manager']
tags:
- { name: breadcrumb_builder, priority: 1001 }
forum.breadcrumb.listing:
class: Drupal\forum\Breadcrumb\ForumListingBreadcrumbBuilder
arguments: ['@entity.manager', '@config.factory', '@forum_manager']
tags:
- { name: breadcrumb_builder, priority: 1001 }
......@@ -2,21 +2,23 @@
/**
* @file
* Contains \Drupal\forum\ForumBreadcrumbBuilder.
* Contains \Drupal\forum\Breadcrumb\ForumBreadcrumbBuilderBase.
*/
namespace Drupal\forum;
namespace Drupal\forum\Breadcrumb;
use Drupal\Core\Breadcrumb\BreadcrumbBuilderBase;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\forum\ForumManagerInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
/**
* Class to define the forum breadcrumb builder.
* Provides a forum breadcrumb base class.
*
* This just holds the dependency-injected config, entity manager, and forum
* manager objects.
*/
class ForumBreadcrumbBuilder extends BreadcrumbBuilderBase {
abstract class ForumBreadcrumbBuilderBase extends BreadcrumbBuilderBase {
/**
* Configuration object for this builder.
......@@ -26,7 +28,7 @@ class ForumBreadcrumbBuilder extends BreadcrumbBuilderBase {
protected $config;
/**
* Stores the Entity manager.
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
......@@ -40,79 +42,32 @@ class ForumBreadcrumbBuilder extends BreadcrumbBuilderBase {
protected $forumManager;
/**
* Constructs a new ForumBreadcrumbBuilder.
* Constructs a forum breadcrumb builder object.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Drupal\forum\ForumManagerInterface $forum_manager
* The forum manager service.
*/
public function __construct(EntityManagerInterface $entity_manager, ConfigFactoryInterface $configFactory, ForumManagerInterface $forum_manager) {
public function __construct(EntityManagerInterface $entity_manager, ConfigFactoryInterface $config_factory, ForumManagerInterface $forum_manager) {
$this->entityManager = $entity_manager;
$this->config = $configFactory->get('forum.settings');
$this->config = $config_factory->get('forum.settings');
$this->forumManager = $forum_manager;
}
/**
* {@inheritdoc}
*/
public function applies(array $attributes) {
return !empty($attributes[RouteObjectInterface::ROUTE_NAME])
&& (($attributes[RouteObjectInterface::ROUTE_NAME] == 'node.view' && isset($attributes['node']) && $this->forumManager->checkNodeType($attributes['node']))
|| ($attributes[RouteObjectInterface::ROUTE_NAME] == 'forum.page' && isset($attributes['taxonomy_term']))
);
}
/**
* {@inheritdoc}
*/
public function build(array $attributes) {
if ($attributes[RouteObjectInterface::ROUTE_NAME] == 'node.view') {
return $this->forumPostBreadcrumb($attributes['node']);
}
elseif ($attributes[RouteObjectInterface::ROUTE_NAME] == 'forum.page') {
return $this->forumTermBreadcrumb($attributes['taxonomy_term']);
}
}
/**
* Builds the breadcrumb for a forum post page.
*/
protected function forumPostBreadcrumb($node) {
$vocabulary = $this->entityManager->getStorageController('taxonomy_vocabulary')->load($this->config->get('vocabulary'));
$breadcrumb[] = $this->l($this->t('Home'), '<front>');
$breadcrumb[] = l($vocabulary->label(), 'forum');
if ($parents = taxonomy_term_load_parents_all($node->forum_tid)) {
$parents = array_reverse($parents);
foreach ($parents as $parent) {
$breadcrumb[] = $this->l($parent->label(), 'forum.page', array('taxonomy_term' => $parent->id()));
}
}
return $breadcrumb;
}
/**
* Builds the breadcrumb for a forum term page.
*/
protected function forumTermBreadcrumb($term) {
$vocabulary = $this->entityManager->getStorageController('taxonomy_vocabulary')->load($this->config->get('vocabulary'));
$vocabulary = $this->entityManager
->getStorageController('taxonomy_vocabulary')
->load($this->config->get('vocabulary'));
$breadcrumb[] = $this->l($vocabulary->label(), 'forum.index');
$breadcrumb[] = $this->l($this->t('Home'), '<front>');
if ($term->tid) {
// Parent of all forums is the vocabulary name.
$breadcrumb[] = $this->l($vocabulary->label(), 'forum.index');
}
// Add all parent forums to breadcrumbs.
if ($term->parents) {
foreach (array_reverse($term->parents) as $parent) {
if ($parent->id() != $term->id()) {
$breadcrumb[] = $this->l($parent->label(), 'forum.page', array('taxonomy_term' => $parent->id()));
}
}
}
return $breadcrumb;
}
......
<?php
/**
* @file
* Contains \Drupal\forum\Breadcrumb\ForumListingBreadcrumbBuilder.
*/
namespace Drupal\forum\Breadcrumb;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
/**
* Provides a breadcrumb builder base class for forum listing pages.
*/
class ForumListingBreadcrumbBuilder extends ForumBreadcrumbBuilderBase {
/**
* {@inheritdoc}
*/
public function applies(array $attributes) {
return !empty($attributes[RouteObjectInterface::ROUTE_NAME])
&& $attributes[RouteObjectInterface::ROUTE_NAME] == 'forum.page'
&& isset($attributes['taxonomy_term']);
}
/**
* {@inheritdoc}
*/
public function build(array $attributes) {
$breadcrumb = parent::build($attributes);
// Add all parent forums to breadcrumbs.
$term_id = $attributes['taxonomy_term']->id();
$parents = $this->forumManager->getParents($term_id);
if ($parents) {
foreach (array_reverse($parents) as $parent) {
if ($parent->id() != $term_id) {
$breadcrumb[] = $this->l($parent->label(), 'forum.page', array(
'taxonomy_term' => $parent->id(),
));
}
}
}
return $breadcrumb;
}
}
<?php
/**
* @file
* Contains \Drupal\forum\Forum\Breadcrumb\ForumNodeBreadcrumbBuilder.
*/
namespace Drupal\forum\Breadcrumb;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
/**
* Breadcrumb builder for forum nodes.
*/
class ForumNodeBreadcrumbBuilder extends ForumBreadcrumbBuilderBase {
/**
* {@inheritdoc}
*/
public function applies(array $attributes) {
return !empty($attributes[RouteObjectInterface::ROUTE_NAME])
&& $attributes[RouteObjectInterface::ROUTE_NAME] == 'node.view'
&& isset($attributes['node'])
&& $this->forumManager->checkNodeType($attributes['node']);
}
/**
* {@inheritdoc}
*/
public function build(array $attributes) {
$breadcrumb = parent::build($attributes);
$parents = $this->forumManager->getParents($attributes['node']->forum_tid);
if ($parents) {
$parents = array_reverse($parents);
foreach ($parents as $parent) {
$breadcrumb[] = $this->l($parent->label(), 'forum.page',
array(
'taxonomy_term' => $parent->id(),
)
);
}
}
return $breadcrumb;
}
}
<?php
/**
* @file
* Contains \Drupal\forum\Tests\Breadcrumb\ForumBreadcrumbBuilderBaseTest.
*/
namespace Drupal\forum\Tests\Breadcrumb;
use Drupal\Tests\UnitTestCase;
/**
* Tests the ForumManager.
*
* @coversDefaultClass \Drupal\forum\Breadcrumb\ForumBreadcrumbBuilderBase
* @group Forum
* @group Drupal
*
* @see \Drupal\forum\ForumManager
*/
class ForumBreadcrumbBuilderBaseTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'Forum Breadcrumb Base Test',
'description' => 'Tests the abstract base class for forum breadcrumbs.',
'group' => 'Forum',
);
}
/**
* Tests ForumBreadcrumbBuilderBase::__construct().
*
* @covers ::__construct()
*/
public function testConstructor() {
// Make some test doubles.
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$config_factory = $this->getConfigFactoryStub(
array(
'forum.settings' => array('IAmATestKey' => 'IAmATestValue'),
)
);
$forum_manager = $this->getMock('Drupal\forum\ForumManagerInterface');
// Make an object to test.
$builder = $this->getMockForAbstractClass(
'Drupal\forum\Breadcrumb\ForumBreadcrumbBuilderBase',
// Constructor array.
array(
$entity_manager,
$config_factory,
$forum_manager,
)
);
// Reflect upon our properties, except for config which is a special case.
$property_names = array(
'entityManager' => $entity_manager,
'forumManager' => $forum_manager,
);
foreach ($property_names as $property_name => $property_value) {
$this->assertAttributeEquals(
$property_value, $property_name, $builder
);
}
// Test that the constructor made a config object with our info in it.
$reflector = new \ReflectionClass($builder);
$ref_property = $reflector->getProperty('config');
$ref_property->setAccessible(TRUE);
$config = $ref_property->getValue($builder);
$this->assertEquals('IAmATestValue', $config->get('IAmATestKey'));
}
/**
* Tests ForumBreadcrumbBuilderBase::build().
*
* @see \Drupal\forum\Breadcrumb\ForumBreadcrumbBuilderBase::build()
*
* @covers ::build
*/
public function testBuild() {
// Build all our dependencies, backwards.
$forum_manager = $this->getMockBuilder('Drupal\forum\ForumManagerInterface')
->disableOriginalConstructor()
->getMock();
$vocab_item = $this->getMock('Drupal\taxonomy\VocabularyInterface');
$vocab_item->expects($this->any())
->method('label')
->will($this->returnValue('Fora_is_the_plural_of_forum'));
$vocab_storage_controller = $this->getMock('Drupal\Core\Entity\EntityStorageControllerInterface');
$vocab_storage_controller->expects($this->any())
->method('load')
->will($this->returnValueMap(array(
array('forums', $vocab_item),
)));
$entity_manager = $this->getMockBuilder('Drupal\Core\Entity\EntityManagerInterface')
->disableOriginalConstructor()
->getMock();
$entity_manager->expects($this->any())
->method('getStorageController')
->will($this->returnValueMap(array(
array('taxonomy_vocabulary', $vocab_storage_controller),
)));
$config_factory = $this->getConfigFactoryStub(
array(
'forum.settings' => array(
'vocabulary' => 'forums',
),
)
);
// Build a breadcrumb builder to test.
$breadcrumb_builder = $this->getMockForAbstractClass(
'Drupal\forum\Breadcrumb\ForumBreadcrumbBuilderBase',
// Constructor array.
array(
$entity_manager,
$config_factory,
$forum_manager,
)
);
// Add a translation manager for t().
$translation_manager = $this->getStringTranslationStub();
$property = new \ReflectionProperty('Drupal\forum\Breadcrumb\ForumNodeBreadcrumbBuilder', 'translationManager');
$property->setAccessible(TRUE);
$property->setValue($breadcrumb_builder, $translation_manager);
// Add a link generator for l().
$link_generator = $this->getMockBuilder('Drupal\Core\Utility\LinkGeneratorInterface')
->disableOriginalConstructor()
->getMock();
$link_generator->expects($this->any())
->method('generate')
->will($this->returnArgument(0));
$property = new \ReflectionProperty('Drupal\forum\Breadcrumb\ForumNodeBreadcrumbBuilder', 'linkGenerator');
$property->setAccessible(TRUE);
$property->setValue($breadcrumb_builder, $link_generator);
// Our empty data set.
$attributes = array();
// Expected result set.
$expected = array(
'Home',
'Fora_is_the_plural_of_forum',
);
// And finally, the test.
$this->assertSame($expected, $breadcrumb_builder->build($attributes));
}
}
<?php
/**
* @file
* Contains \Drupal\forum\Tests\Breadcrumb\ForumListingBreadcrumbBuilderTest.
*/
namespace Drupal\forum\Tests\Breadcrumb;
use Drupal\Tests\UnitTestCase;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
/**
* Tests the listing class for forum breadcrumbs.
*
* @coversDefaultClass \Drupal\forum\Breadcrumb\ForumListingBreadcrumbBuilder
* @group Forum
* @group Drupal
*
* @see \Drupal\forum\ForumListingBreadcrumbBuilder
*/
class ForumListingBreadcrumbBuilderTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'Forum Breadcrumb Listing Test',
'description' => 'Tests the listing class for forum breadcrumbs.',
'group' => 'Forum',
);
}
/**
* Tests ForumListingBreadcrumbBuilder::applies().
*
* @param bool $expected
* ForumListingBreadcrumbBuilder::applies() expected result.
* @param array $attributes
* ForumListingBreadcrumbBuilder::applies() $attributes parameter.
*
* @dataProvider providerTestApplies
* @covers ::applies
*/
public function testApplies($expected, $attributes) {
// Make some test doubles.
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$config_factory = $this->getConfigFactoryStub(array());
$forum_manager = $this->getMock('Drupal\forum\ForumManagerInterface');
// Make an object to test.
$builder = $this->getMockBuilder('Drupal\forum\Breadcrumb\ForumListingBreadcrumbBuilder')
->setConstructorArgs(array(
$entity_manager,
$config_factory,
$forum_manager,
))
->setMethods(NULL)
->getMock();
$this->assertEquals($expected, $builder->applies($attributes));
}
/**
* Provides test data for testApplies().
*
* @return array
* Array of datasets for testApplies(). Structured as such:
* - ForumListBreadcrumbBuilder::applies() expected result.
* - ForumListBreadcrumbBuilder::applies() $attributes input array.
*/
public function providerTestApplies() {
// Send a Node mock, because NodeInterface cannot be mocked.
$mock_term = $this->getMockBuilder('Drupal\taxonomy\Entity\Term')
->disableOriginalConstructor()
->getMock();
return array(
array(
FALSE,
array(),
),
array(
FALSE,
array(
RouteObjectInterface::ROUTE_NAME => 'NOT.forum.page',
),
),
array(
FALSE,
array(
RouteObjectInterface::ROUTE_NAME => 'forum.page',
),
),
array(
TRUE,
array(
RouteObjectInterface::ROUTE_NAME => 'forum.page',
'taxonomy_term' => 'anything',
),
),
array(
TRUE,
array(
RouteObjectInterface::ROUTE_NAME => 'forum.page',
'taxonomy_term' => $mock_term,
),
),
);
}
/**
* Tests ForumListingBreadcrumbBuilder::build().
*
* @see \Drupal\forum\ForumListingBreadcrumbBuilder::build()
*
* @covers ::build
*/
public function testBuild() {
// Build all our dependencies, backwards.
$term1 = $this->getMockBuilder('Drupal\taxonomy\Entity\Term')
->disableOriginalConstructor()
->getMock();
$term1->expects($this->any())
->method('label')
->will($this->returnValue('Something'));
$term1->expects($this->any())
->method('id')
->will($this->returnValue(1));
$term2 = $this->getMockBuilder('Drupal\taxonomy\Entity\Term')
->disableOriginalConstructor()
->getMock();
$term2->expects($this->any())
->method('label')
->will($this->returnValue('Something else'));
$term2->expects($this->any())
->method('id')
->will($this->returnValue(2));
$forum_manager = $this->getMock('Drupal\forum\ForumManagerInterface');
$forum_manager->expects($this->at(0))
->method('getParents')
->will($this->returnValue(array($term1)));
$forum_manager->expects($this->at(1))
->method('getParents')
->will($this->returnValue(array($term1, $term2)));
// The root forum.
$vocab_item = $this->getMock('Drupal\taxonomy\VocabularyInterface');
$vocab_item->expects($this->any())
->method('label')
->will($this->returnValue('Fora_is_the_plural_of_forum'));
$vocab_storage_controller = $this->getMock('Drupal\Core\Entity\EntityStorageControllerInterface');
$vocab_storage_controller->expects($this->any())
->method('load')
->will($this->returnValueMap(array(
array('forums', $vocab_item),
)));
$entity_manager = $this->getMockBuilder('Drupal\Core\Entity\EntityManagerInterface')
->disableOriginalConstructor()
->getMock();
$entity_manager->expects($this->any())
->method('getStorageController')
->will($this->returnValueMap(array(
array('taxonomy_vocabulary', $vocab_storage_controller),
)));
$config_factory = $this->getConfigFactoryStub(
array(
'forum.settings' => array(
'vocabulary' => 'forums',
),
)
);
// Build a breadcrumb builder to test.
$breadcrumb_builder = $this->getMock(
'Drupal\forum\Breadcrumb\ForumListingBreadcrumbBuilder', NULL, array(
$entity_manager,
$config_factory,
$forum_manager,
)
);
// Add a translation manager for t().
$translation_manager = $this->getStringTranslationStub();
$property = new \ReflectionProperty('Drupal\forum\Breadcrumb\ForumNodeBreadcrumbBuilder', 'translationManager');
$property->setAccessible(TRUE);
$property->setValue($breadcrumb_builder, $translation_manager);
// Add a link generator for l().
$link_generator = $this->getMockBuilder('Drupal\Core\Utility\LinkGeneratorInterface')
->disableOriginalConstructor()
->getMock();
$link_generator->expects($this->any())
->method('generate')
->will($this->returnArgument(0));
$property = new \ReflectionProperty('Drupal\forum\Breadcrumb\ForumNodeBreadcrumbBuilder', 'linkGenerator');
$property->setAccessible(TRUE);
$property->setValue($breadcrumb_builder, $link_generator);
// The forum listing we need a breadcrumb back from.
$forum_listing = $this->getMockBuilder('Drupal\taxonomy\Entity\Term')
->disableOriginalConstructor()
->getMock();
$forum_listing->tid = 23;
$forum_listing->expects($this->any())
->method('label')
->will($this->returnValue('You_should_not_see_this'));
// Our data set.
$attributes = array(
'taxonomy_term' => $forum_listing,
);
// First test.
$expected1 = array(
'Home',
'Fora_is_the_plural_of_forum',
'Something',
);
$this->assertSame($expected1, $breadcrumb_builder->build($attributes));
// Second test.
$expected2 = array(
'Home',
'Fora_is_the_plural_of_forum',
'Something else',
'Something',
);
$this->assertSame($expected2, $breadcrumb_builder->build($attributes));
}
}