Commit 82e13a43 authored by borisson_'s avatar borisson_ Committed by borisson_

Issue #2846294 by borisson_, jummonk, shylajaphp: Facets summary breaks hierarchical facets

parent e74b8741
......@@ -153,7 +153,31 @@ class DefaultFacetsSummaryManager {
return $return;
});
/** @var \Drupal\facets\Result\Result $result */
$build['#items'] = $this->buildResultTree($results);
// Allow our Facets Summary processors to alter the build array in a
// configured order.
foreach ($facets_summary->getProcessorsByStage(ProcessorInterface::STAGE_BUILD) as $processor) {
if (!$processor instanceof BuildProcessorInterface) {
throw new InvalidProcessorException("The processor {$processor->getPluginDefinition()['id']} has a build definition but doesn't implement the required BuildProcessorInterface interface");
}
$build = $processor->build($facets_summary, $build, $facets);
}
return $build;
}
/**
* Build result tree, taking possible children into account.
*
* @param array $results
* Facet results array.
*
* @return array
* Facet render items.
*/
protected function buildResultTree($results) {
$items = [];
foreach ($results as $result) {
if ($result->isActive()) {
$item = [
......@@ -164,20 +188,13 @@ class DefaultFacetsSummaryManager {
'#is_active' => TRUE,
];
$item = (new Link($item, $result->getUrl()))->toRenderable();
$build['#items'][] = $item;
$items[] = $item;
}
}
// Allow our Facets Summary processors to alter the build array in a
// configured order.
foreach ($facets_summary->getProcessorsByStage(ProcessorInterface::STAGE_BUILD) as $processor) {
if (!$processor instanceof BuildProcessorInterface) {
throw new InvalidProcessorException("The processor {$processor->getPluginDefinition()['id']} has a build definition but doesn't implement the required BuildProcessorInterface interface");
if ($children = $result->getChildren()) {
$items = array_merge($items, $this->buildResultTree($children));
}
$build = $processor->build($facets_summary, $build, $facets);
}
return $build;
return $items;
}
}
<?php
namespace Drupal\Tests\facets_summary\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Language\LanguageInterface;
use Drupal\search_api\Item\Field;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Tests\TaxonomyTestTrait;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\Tests\facets\Functional\FacetsTestBase;
/**
* Tests the hierarchical facets implementation.
*
* @group facets
*/
class HierarchicalFacetIntegrationTest extends FacetsTestBase {
use TaxonomyTestTrait;
use EntityReferenceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = [
'facets_summary',
];
/**
* Drupal vocabulary.
*
* @var \Drupal\taxonomy\Entity\Vocabulary
*/
protected $vocabulary;
/**
* The fieldname for the referenced term.
*
* @var string
*/
protected $fieldName;
/**
* Uri to the facets edit page.
*
* @var string
*/
protected $facetEditPage;
/**
* An array of taxonomy terms.
*
* @var \Drupal\taxonomy\Entity\Term[]
*/
protected $parents = [];
/**
* An array of taxonomy terms.
*
* @var \Drupal\taxonomy\Entity\Term[]
*/
protected $terms = [];
/**
* {@inheritdoc}
*/
protected $strictConfigSchema = FALSE;
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
// Make absolutely sure the ::$blocks variable doesn't pass information
// along between tests.
$this->blocks = NULL;
$this->drupalLogin($this->adminUser);
// Create hierarchical terms in a new vocabulary.
$this->vocabulary = $this->createVocabulary();
$this->createHierarchialTermStructure();
// Default content that is extended with a term reference field below.
$this->setUpExampleStructure();
// Create a taxonomy_term_reference field on the article and item.
$this->fieldName = Unicode::strtolower($this->randomMachineName());
$fieldLabel = $this->randomString();
$this->createEntityReferenceField('entity_test_mulrev_changed', 'article', $this->fieldName, $fieldLabel, 'taxonomy_term');
$this->createEntityReferenceField('entity_test_mulrev_changed', 'item', $this->fieldName, $fieldLabel, 'taxonomy_term');
$this->insertExampleContent();
// Add fields to index.
$index = $this->getIndex();
// Index the taxonomy and entity reference fields.
$term_field = new Field($index, $this->fieldName);
$term_field->setType('integer');
$term_field->setPropertyPath($this->fieldName);
$term_field->setDatasourceId('entity:entity_test_mulrev_changed');
$term_field->setLabel($fieldLabel);
$index->addField($term_field);
$index->save();
$this->indexItems($this->indexId);
$facet_name = 'hierarchical facet';
$facet_id = 'hierarchical_facet';
$this->facetEditPage = 'admin/config/search/facets/' . $facet_id . '/edit';
$this->createFacet($facet_name, $facet_id, $this->fieldName);
}
/**
* Test the hierarchical facets functionality.
*/
public function testHierarchicalFacet() {
// Verify that the link to the index processors settings page is available.
$this->drupalGet($this->facetEditPage);
$this->clickLink('Search api index processor configuration');
$this->assertResponse(200);
// Enable hierarchical facets and translation of entity ids to its names for
// a better readability.
$this->drupalGet($this->facetEditPage);
$edit = [
'facet_settings[use_hierarchy]' => '1',
'facet_settings[translate_entity][status]' => TRUE,
];
$this->drupalPostForm(NULL, $edit, 'Save');
$values = [
'name' => 'Owl',
'id' => 'owl',
'facet_source_id' => 'search_api:views_page__search_api_test_view__page_1',
];
$this->drupalPostForm('admin/config/search/facets/add-facet-summary', $values, 'Save');
$this->drupalPostForm(NULL, [], 'Save');
$block = [
'region' => 'footer',
'id' => str_replace('_', '-', 'owl'),
'weight' => 50,
];
$block = $this->drupalPlaceBlock('facets_summary_block:owl', $block);
// Child elements should be collapsed and invisible.
$this->drupalGet('search-api-test-fulltext');
$this->assertFacetBlocksAppear();
$this->assertFacetLabel('Parent 1');
$this->assertFacetLabel('Parent 2');
$this->assertNoLink('Child 1');
$this->assertNoLink('Child 2');
$this->assertNoLink('Child 3');
$this->assertNoLink('Child 4');
$this->assertText($block->label());
// Click the first parent and make sure its children are visible.
$this->clickLink('Parent 1');
$this->assertFacetBlocksAppear();
$this->checkFacetIsActive('Parent 1');
$this->assertFacetLabel('Child 1');
$this->assertFacetLabel('Child 2');
$this->assertNoLink('Child 3');
$this->assertNoLink('Child 4');
$this->assertText($block->label());
}
/**
* Setup a term structure for our test.
*/
protected function createHierarchialTermStructure() {
// Generate 2 parent terms.
foreach (['Parent 1', 'Parent 2'] as $name) {
$this->parents[$name] = Term::create([
'name' => $name,
'description' => '',
'vid' => $this->vocabulary->id(),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
]);
$this->parents[$name]->save();
}
// Generate 4 child terms.
for ($i = 1; $i <= 4; $i++) {
$this->terms[$i] = Term::create([
'name' => sprintf('Child %d', $i),
'description' => '',
'vid' => $this->vocabulary->id(),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
]);
$this->terms[$i]->save();
}
// Build up the hierarchy.
$this->terms[1]->parent = [$this->parents['Parent 1']->id()];
$this->terms[1]->save();
$this->terms[2]->parent = [$this->parents['Parent 1']->id()];
$this->terms[2]->save();
$this->terms[3]->parent = [$this->parents['Parent 2']->id()];
$this->terms[3]->save();
$this->terms[4]->parent = [$this->parents['Parent 2']->id()];
$this->terms[4]->save();
}
/**
* Creates several test entities with the term-reference field.
*/
protected function insertExampleContent() {
$entity_test_storage = \Drupal::entityTypeManager()
->getStorage('entity_test_mulrev_changed');
$this->entities[1] = $entity_test_storage->create(array(
'name' => 'foo bar baz',
'body' => 'test test',
'type' => 'item',
'keywords' => array('orange'),
'category' => 'item_category',
$this->fieldName => [$this->parents['Parent 1']->id()],
));
$this->entities[1]->save();
$this->entities[2] = $entity_test_storage->create(array(
'name' => 'foo test',
'body' => 'bar test',
'type' => 'item',
'keywords' => array('orange', 'apple', 'grape'),
'category' => 'item_category',
$this->fieldName => [$this->parents['Parent 2']->id()],
));
$this->entities[2]->save();
$this->entities[3] = $entity_test_storage->create(array(
'name' => 'bar',
'body' => 'test foobar',
'type' => 'item',
$this->fieldName => [$this->terms[1]->id()],
));
$this->entities[3]->save();
$this->entities[4] = $entity_test_storage->create(array(
'name' => 'foo baz',
'body' => 'test test test',
'type' => 'article',
'keywords' => array('apple', 'strawberry', 'grape'),
'category' => 'article_category',
$this->fieldName => [$this->terms[2]->id()],
));
$this->entities[4]->save();
$this->entities[5] = $entity_test_storage->create(array(
'name' => 'bar baz',
'body' => 'foo',
'type' => 'article',
'keywords' => array('orange', 'strawberry', 'grape', 'banana'),
'category' => 'article_category',
$this->fieldName => [$this->terms[3]->id()],
));
$this->entities[5]->save();
$this->entities[6] = $entity_test_storage->create(array(
'name' => 'bar baz',
'body' => 'foo',
'type' => 'article',
'keywords' => array('orange', 'strawberry', 'grape', 'banana'),
'category' => 'article_category',
$this->fieldName => [$this->terms[4]->id()],
));
$this->entities[6]->save();
}
/**
* Convert facet name to machine name.
*
* @param string $facet_name
* The name of the facet.
*
* @return string
* The facet name changed to a machine name.
*/
protected function convertNameToMachineName($facet_name) {
return preg_replace('@[^a-zA-Z0-9_]+@', '_', strtolower($facet_name));
}
}
......@@ -267,7 +267,7 @@ class IntegrationTest extends FacetsTestBase {
$this->drupalPlaceBlock('facets_summary_block:show_count', ['region' => 'footer', 'id' => 'show-count']);
$this->drupalGet('search-api-test-fulltext');
$this->assertSession()->pageTextNotContains('5 results found');
$this->assertSession()->pageTextContains('5 results found');
$this->clickLink('apple');
$this->assertSession()->pageTextContains('2 results found');
......
......@@ -430,6 +430,14 @@ class DefaultFacetManager {
if (isset($keyed_results[$child_id])) {
$child_keyed_results[$child_id] = $keyed_results[$child_id];
}
else {
// Children could already be built by Facets Summary manager, if
// they are, just loading them will suffice.
$children = $keyed_results[$current_id]->getChildren();
if (!empty($children[$child_id])) {
$child_keyed_results[$child_id] = $children[$child_id];
}
}
}
$result->setChildren($child_keyed_results);
$this->childIds = array_merge($this->childIds, $child_ids);
......
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