From 4ca0a838e17901451cc255ea233a98bead04ae05 Mon Sep 17 00:00:00 2001 From: jax <jax@11450.no-reply.drupal.org> Date: Fri, 17 Jul 2020 21:43:20 +0200 Subject: [PATCH] Issue #2844895 by Jeroen_005, tamarpe, Jax, borisson_, gaurav.kapoor: Transform entity id into label doesn't work with aggregated fields --- ...ranslateEntityAggregatedFieldProcessor.php | 232 ++++++++++++++++++ .../Functional/ProcessorIntegrationTest.php | 1 + 2 files changed, 233 insertions(+) create mode 100644 src/Plugin/facets/processor/TranslateEntityAggregatedFieldProcessor.php diff --git a/src/Plugin/facets/processor/TranslateEntityAggregatedFieldProcessor.php b/src/Plugin/facets/processor/TranslateEntityAggregatedFieldProcessor.php new file mode 100644 index 00000000..f2d11540 --- /dev/null +++ b/src/Plugin/facets/processor/TranslateEntityAggregatedFieldProcessor.php @@ -0,0 +1,232 @@ +<?php + +namespace Drupal\facets\Plugin\facets\processor; + +use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Config\ConfigManagerInterface; +use Drupal\Core\Entity\EntityFieldManagerInterface; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\facets\FacetInterface; +use Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay; +use Drupal\facets\Processor\BuildProcessorInterface; +use Drupal\facets\Processor\ProcessorPluginBase; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\TypedData\TranslatableInterface; + +/** + * Transforms the results to show the translated entity label. + * + * @FacetsProcessor( + * id = "translate_entity_aggregated_fields", + * label = @Translation("Transform entity ID in aggregated field to label"), + * description = @Translation("Display the entity label instead of its ID (for example the term name instead of the taxonomy term ID) in aggregated fields."), + * stages = { + * "build" = 5 + * } + * ) + */ +class TranslateEntityAggregatedFieldProcessor extends ProcessorPluginBase implements BuildProcessorInterface, ContainerFactoryPluginInterface { + + /** + * The language manager. + * + * @var \Drupal\Core\Language\LanguageManagerInterface + */ + protected $languageManager; + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * The config manager. + * + * @var \Drupal\Core\Config\ConfigManagerInterface + */ + protected $configManager; + + /** + * The entity field manager. + * + * @var \Drupal\Core\Entity\EntityFieldManagerInterface + */ + protected $entityFieldManager; + + /** + * The entity_type bundle info service. + * + * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface + */ + protected $entityTypeBundleInfo; + + /** + * Constructs a Drupal\Component\Plugin\PluginBase object. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager + * The language manager. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + * @param \Drupal\Core\Config\ConfigManagerInterface $config_manager + * The config manager. + * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager + * The entity field manager. + * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info + * The entity bundle info service. + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManagerInterface $language_manager, EntityTypeManagerInterface $entity_type_manager, ConfigManagerInterface $config_manager, EntityFieldManagerInterface $entity_field_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + $this->languageManager = $language_manager; + $this->entityTypeManager = $entity_type_manager; + $this->configManager = $config_manager; + $this->entityFieldManager = $entity_field_manager; + $this->entityTypeBundleInfo = $entity_type_bundle_info; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('language_manager'), + $container->get('entity_type.manager'), + $container->get('config.manager'), + $container->get('entity_field.manager'), + $container->get('entity_type.bundle.info') + ); + } + + /** + * {@inheritdoc} + */ + public function build(FacetInterface $facet, array $results) { + $field_identifier = $facet->getFieldIdentifier(); + $entity_type_ids = []; + $allowed_values = []; + $language_interface = $this->languageManager->getCurrentLanguage(); + + // Support multiple entities when using Search API. + 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); + + foreach ($field->getConfiguration()['fields'] as $field_configuration) { + $parts = explode(':', $field_configuration); + if ($parts[0] !== 'entity') { + throw new \InvalidArgumentException('Data type must be in the form of "entity:ENTITY_TYPE/FIELD_NAME."'); + } + $parts = explode('/', $parts[1]); + $entity_type_id = $parts[0]; + $field = $parts[1]; + $entity_type_ids[] = $entity_type_id; + + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + $field_storage = $definition_update_manager->getFieldStorageDefinition($field, $entity_type_id); + if ($field_storage && $field_storage->getType() === 'entity_reference') { + /** @var \Drupal\facets\Result\ResultInterface $result */ + $ids = []; + foreach ($results as $delta => $result) { + $ids[$delta] = $result->getRawValue(); + } + + if ($field_storage instanceof FieldStorageDefinitionInterface) { + if ($field !== 'type') { + // Load all indexed entities of this type. + $entities = $this->entityTypeManager + ->getStorage($field_storage->getSettings()['target_type']) + ->loadMultiple($ids); + + // Loop over all results. + foreach ($results as $i => $result) { + if (!isset($entities[$ids[$i]])) { + continue; + } + + /** @var \Drupal\Core\Entity\ContentEntityBase $entity */ + $entity = $entities[$ids[$i]]; + // Check for a translation of the entity and load that + // instead if one's found. + if ($entity instanceof TranslatableInterface && $entity->hasTranslation($language_interface->getId())) { + $entity = $entity->getTranslation($language_interface->getId()); + } + + // Overwrite the result's display value. + $results[$i]->setDisplayValue($entity->label()); + } + } + } + } + } + // If no values are found for the current field, try to see if this is a + // bundle field. + foreach ($entity_type_ids as $entity) { + $list_bundles = $this->entityTypeBundleInfo->getBundleInfo($entity); + if (!empty($list_bundles)) { + foreach ($list_bundles as $key => $bundle) { + $allowed_values[$key] = $bundle['label']; + } + $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 original + * 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; + } + + /** + * {@inheritdoc} + */ + public function supportsFacet(FacetInterface $facet) { + $field_identifier = $facet->getFieldIdentifier(); + /** @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->getPropertyPath() === 'aggregated_field') { + return TRUE; + } + + return FALSE; + } + +} diff --git a/tests/src/Functional/ProcessorIntegrationTest.php b/tests/src/Functional/ProcessorIntegrationTest.php index 536edeef..d55f4e2b 100644 --- a/tests/src/Functional/ProcessorIntegrationTest.php +++ b/tests/src/Functional/ProcessorIntegrationTest.php @@ -860,6 +860,7 @@ class ProcessorIntegrationTest extends FacetsTestBase { $hiddenProcessors = [ 'boolean_item', 'translate_entity', + 'translate_entity_aggregated_fields', 'uid_to_username_callback', ]; if (in_array($processor->getPluginId(), $hiddenProcessors)) { -- GitLab