Commit aeec56f7 authored by git's avatar git Committed by borisson_
Browse files

Issue #2773113 by borisson_, ndrake86, YurkinPark, swentel: Using the List...

Issue #2773113 by borisson_, ndrake86, YurkinPark, swentel: Using the List Value processor to display label for Search API Fields throws an error
parent 3feb060c
......@@ -87,3 +87,6 @@ plugin.plugin_configuration.facets_processor.hide_non_narrowing_result_processor
plugin.plugin_configuration.facets_processor.hide_active_items_processor:
type: config_object
plugin.plugin_configuration.facets_processor.list_item:
type: config_object
......@@ -5,10 +5,13 @@ namespace Drupal\facets\Plugin\facets\processor;
use Drupal\Core\Config\ConfigManagerInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\facets\Exception\InvalidProcessorException;
use Drupal\facets\FacetInterface;
use Drupal\facets\FacetSource\SearchApiFacetSourceInterface;
use Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay;
use Drupal\facets\Processor\BuildProcessorInterface;
use Drupal\facets\Processor\ProcessorPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -92,10 +95,14 @@ class ListItemProcessor extends ProcessorPluginBase implements BuildProcessorInt
public function build(FacetInterface $facet, array $results) {
$field_identifier = $facet->getFieldIdentifier();
$entity = 'node';
$field = FALSE;
$allowed_values = [];
// Support multiple entities when using Search API.
if ($facet->getFacetSource() instanceof SearchApiFacetSourceInterface) {
if ($facet->getFacetSource() instanceof SearchApiDisplay) {
/** @var \Drupal\search_api\Entity\Index $index */
$index = $facet->getFacetSource()->getIndex();
/** @var \Drupal\search_api\Item\Field $field */
$field = $index->getField($field_identifier);
if (!$field->getDatasourceId()) {
......@@ -103,7 +110,6 @@ class ListItemProcessor extends ProcessorPluginBase implements BuildProcessorInt
}
$entity = $field->getDatasource()->getEntityTypeId();
}
// If it's an entity base field, we find it in the field definitions.
// We don't have access to the bundle via SearchApiFacetSourceInterface, so
// we check the entity's base fields only.
......@@ -111,43 +117,76 @@ class ListItemProcessor extends ProcessorPluginBase implements BuildProcessorInt
// This only works for configurable fields.
$config_entity_name = sprintf('field.storage.%s.%s', $entity, $field_identifier);
if (isset($base_fields[$field_identifier])) {
$field = $base_fields[$field_identifier];
}
elseif ($this->configManager->loadConfigEntityByName($config_entity_name) !== NULL) {
$field = $this->configManager->loadConfigEntityByName($config_entity_name);
}
// Fields defined in code don't cant be loaded from storage so check the
// fields property path and see if its part of the base fields.
elseif ($field->getDataDefinition() instanceof FieldItemDataDefinition) {
$fieldDefinition = $field->getDataDefinition()
->getFieldDefinition();
$referenced_entity_name = sprintf(
'field.storage.%s.%s',
$fieldDefinition->getTargetEntityTypeId(),
$fieldDefinition->getName()
);
if ($fieldDefinition instanceof BaseFieldDefinition) {
if (isset($base_fields[$field->getPropertyPath()])) {
$field = $base_fields[$field->getPropertyPath()];
}
if ($field) {
$function = $field->getSetting('allowed_values_function');
if (empty($function)) {
$allowed_values = $field->getSetting('allowed_values');
}
else {
$allowed_values = ${$function}($field);
// Diggs down to get the referenced field the entity reference is based
// on.
elseif ($this->configManager->loadConfigEntityByName($referenced_entity_name) !== NULL) {
$field = $this->configManager
->loadConfigEntityByName($referenced_entity_name);
}
// If no values are found for the current field, try to see if this is a
// bundle field.
if (empty($allowed_values) && $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity)) {
foreach ($bundles as $key => $bundle) {
$allowed_values[$key] = $bundle['label'];
}
if ($field instanceof FieldStorageDefinitionInterface) {
if ($field->getName() !== 'type') {
$allowed_values = options_allowed_values($field);
if (!empty($allowed_values)) {
return $this->overWriteDisplayValues($results, $allowed_values);
}
}
if (is_array($allowed_values)) {
/** @var \Drupal\facets\Result\ResultInterface $result */
foreach ($results as &$result) {
if (isset($allowed_values[$result->getRawValue()])) {
$result->setDisplayValue($allowed_values[$result->getRawValue()]);
}
}
}
// If no values are found for the current field, try to see if this is a
// bundle field.
$list_bundles = $this->entityTypeBundleInfo->getBundleInfo($entity);
if (!empty($list_bundles)) {
foreach ($list_bundles as $key => $bundle) {
$allowed_values[$key] = $bundle['label'];
}
return $this->overWriteDisplayValues($results, $allowed_values);
}
return $results;
}
/**
* Overwrite the display value of the result with a new text.
*
* @param \Drupal\facets\Result\ResultInterface[] $results
* An array of results to work on.
* @param array $replacements
* An array of values that contain possible replacements for the orignal
* values.
*
* @return \Drupal\facets\Result\ResultInterface[]
* The changed results.
*/
protected function overWriteDisplayValues(array $results, array $replacements) {
/** @var \Drupal\facets\Result\ResultInterface $a */
foreach ($results as &$a) {
if (isset($replacements[$a->getRawValue()])) {
$a->setDisplayValue($replacements[$a->getRawValue()]);
}
}
return $results;
}
}
......@@ -227,7 +227,7 @@ class IntegrationTest extends FacetsTestBase {
$this->blocks[$facet_id] = $this->createBlock($facet_id);
$this->blocks[$depending_facet_id] = $this->createBlock($depending_facet_id);
// Go the the view and test that both facets are shown. Item and article
// Go to the view and test that both facets are shown. Item and article
// come from the DependableFacet, orange and grape come from DependingFacet.
$this->drupalGet('search-api-test-fulltext');
$this->assertFacetLabel('grape');
......
......@@ -20,6 +20,13 @@ class ProcessorIntegrationTest extends FacetsTestBase {
*/
protected $editForm;
/**
* {@inheritdoc}
*/
public static $modules = [
'options',
];
/**
* {@inheritdoc}
*/
......@@ -592,4 +599,45 @@ class ProcessorIntegrationTest extends FacetsTestBase {
$this->drupalPostForm($path, $settings, 'Save');
}
/**
* Checks if the list processor changes machine name to the display label.
*/
public function testListProcessor() {
entity_test_create_bundle('basic', "Basic page", 'entity_test_mulrev_changed');
$entity_test_storage = \Drupal::entityTypeManager()
->getStorage('entity_test_mulrev_changed');
// Add an entity with basic page content type.
$entity_test_storage->create([
'name' => 'AC0871108',
'body' => 'Eamus Catuli',
'type' => 'basic',
])->save();
$this->indexItems($this->indexId);
$facet_name = "Eamus Catuli";
$facet_id = "eamus_catuli";
$editForm = 'admin/config/search/facets/' . $facet_id . '/edit';
$this->createFacet($facet_name, $facet_id);
// Go to the overview and check that the machine names are used as facets.
$this->drupalGet('search-api-test-fulltext');
$this->assertText('Displaying 11 search results');
$this->assertFacetLabel('basic');
// Edit the facet to use the list_item processor.
$edit = [
'facet_settings[list_item][status]' => TRUE,
];
$this->drupalPostForm($editForm, $edit, 'Save');
$this->assertResponse(200);
$this->assertFieldChecked('edit-facet-settings-list-item-status');
// Go back to the overview and check that now the label is being used
// instead.
$this->drupalGet('search-api-test-fulltext');
$this->assertText('Displaying 11 search results');
$this->assertFacetLabel('Basic page');
}
}
......@@ -57,34 +57,23 @@ class ListItemProcessorTest extends UnitTestCase {
->disableOriginalConstructor()
->getMock();
$processor_id = 'list_item';
$this->processor = new ListItemProcessor([], $processor_id, [], $config_manager, $entity_field_manager, $entity_type_bundle_info);
$this->processor = new ListItemProcessor([], 'list_item', [], $config_manager, $entity_field_manager, $entity_type_bundle_info);
}
/**
* Tests facet build with field.module field.
*/
public function testFacetFieldmoduleBuild() {
public function testBuildConfigurableField() {
$module_field = $this->getMockBuilder(FieldStorageConfig::class)
->disableOriginalConstructor()
->getMock();
$module_field->expects($this->at(0))
->method('getSetting')
->with('allowed_values_function')
->willReturn('');
$module_field->expects($this->at(1))
->method('getSetting')
->with('allowed_values')
->willReturn([
1 => 'llama',
2 => 'badger',
3 => 'kitten',
]);
// Make sure that when the processor calls loadConfigEntityByName the field
// we created here is called.
$config_manager = $this->getMockBuilder(ConfigManager::class)
->disableOriginalConstructor()
->getMock();
$config_manager->expects($this->any())
$config_manager->expects($this->exactly(2))
->method('loadConfigEntityByName')
->willReturn($module_field);
......@@ -96,8 +85,7 @@ class ListItemProcessorTest extends UnitTestCase {
->disableOriginalConstructor()
->getMock();
$processor_id = 'list_item';
$processor = new ListItemProcessor([], $processor_id, [], $config_manager, $entity_field_manager, $entity_type_bundle_info);
$processor = new ListItemProcessor([], 'list_item', [], $config_manager, $entity_field_manager, $entity_type_bundle_info);
// Config entity field facet.
$module_field_facet = new Facet([], 'facets_facet');
......@@ -120,23 +108,15 @@ class ListItemProcessorTest extends UnitTestCase {
/**
* Tests facet build with field.module field.
*/
public function testBundle() {
public function testBuildBundle() {
$module_field = $this->getMockBuilder(FieldStorageConfig::class)
->disableOriginalConstructor()
->getMock();
$module_field->expects($this->at(0))
->method('getSetting')
->with('allowed_values_function')
->willReturn([]);
$module_field->expects($this->at(1))
->method('getSetting')
->with('allowed_values')
->willReturn([]);
$config_manager = $this->getMockBuilder(ConfigManager::class)
->disableOriginalConstructor()
->getMock();
$config_manager->expects($this->any())
$config_manager->expects($this->exactly(2))
->method('loadConfigEntityByName')
->willReturn($module_field);
......@@ -147,16 +127,8 @@ class ListItemProcessorTest extends UnitTestCase {
$entity_type_bundle_info = $this->getMockBuilder(EntityTypeBundleInfo::class)
->disableOriginalConstructor()
->getMock();
$entity_type_bundle_info->expects($this->exactly(1))
->method('getBundleInfo')
->willReturn([
1 => ['label' => 'Monkey'],
2 => ['label' => 'Donkey'],
3 => ['label' => 'Kong'],
]);
$processor_id = 'list_item';
$processor = new ListItemProcessor([], $processor_id, [], $config_manager, $entity_field_manager, $entity_type_bundle_info);
$processor = new ListItemProcessor([], 'list_item', [], $config_manager, $entity_field_manager, $entity_type_bundle_info);
// Config entity field facet.
$module_field_facet = new Facet([], 'facets_facet');
......@@ -171,15 +143,15 @@ class ListItemProcessorTest extends UnitTestCase {
$module_field_results = $processor->build($module_field_facet, $this->results);
$this->assertCount(3, $module_field_results);
$this->assertEquals('Monkey', $module_field_results[0]->getDisplayValue());
$this->assertEquals('Donkey', $module_field_results[1]->getDisplayValue());
$this->assertEquals('Kong', $module_field_results[2]->getDisplayValue());
$this->assertEquals('llama', $module_field_results[0]->getDisplayValue());
$this->assertEquals('badger', $module_field_results[1]->getDisplayValue());
$this->assertEquals('kitten', $module_field_results[2]->getDisplayValue());
}
/**
* Tests facet build with base props.
*/
public function testFacetBasepropBuild() {
public function testBuildBaseField() {
$config_manager = $this->getMockBuilder(ConfigManager::class)
->disableOriginalConstructor()
->getMock();
......@@ -187,19 +159,6 @@ class ListItemProcessorTest extends UnitTestCase {
$base_field = $this->getMockBuilder(BaseFieldDefinition::class)
->disableOriginalConstructor()
->getMock();
$base_field->expects($this->any())
->method('getSetting')
->willReturnMap([
['allowed_values_function', ''],
[
'allowed_values',
[
1 => 'blue whale',
2 => 'lynx',
3 => 'dog-wolf-lion',
],
],
]);
$entity_field_manager = $this->getMockBuilder(EntityFieldManager::class)
->disableOriginalConstructor()
......@@ -215,8 +174,7 @@ class ListItemProcessorTest extends UnitTestCase {
->disableOriginalConstructor()
->getMock();
$processor_id = 'list_item';
$processor = new ListItemProcessor([], $processor_id, [], $config_manager, $entity_field_manager, $entity_type_bundle_info);
$processor = new ListItemProcessor([], 'list_item', [], $config_manager, $entity_field_manager, $entity_type_bundle_info);
// Base prop facet.
$base_prop_facet = new Facet([], 'facets_facet');
......@@ -232,9 +190,9 @@ class ListItemProcessorTest extends UnitTestCase {
$base_prop_results = $processor->build($base_prop_facet, $this->results);
$this->assertCount(3, $base_prop_results);
$this->assertEquals('blue whale', $base_prop_results[0]->getDisplayValue());
$this->assertEquals('lynx', $base_prop_results[1]->getDisplayValue());
$this->assertEquals('dog-wolf-lion', $base_prop_results[2]->getDisplayValue());
$this->assertEquals('llama', $base_prop_results[0]->getDisplayValue());
$this->assertEquals('badger', $base_prop_results[1]->getDisplayValue());
$this->assertEquals('kitten', $base_prop_results[2]->getDisplayValue());
}
/**
......@@ -267,3 +225,20 @@ class ListItemProcessorTest extends UnitTestCase {
}
}
namespace Drupal\facets\Plugin\facets\processor;
if (!function_exists('options_allowed_values')) {
/**
* Overwrite the global function with a version that returns the test values.
*/
function options_allowed_values() {
return [
1 => 'llama',
2 => 'badger',
3 => 'kitten',
];
}
}
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