Posting this as a potential use case for #2851851: Facet source plugins should provide metadata for facet fields. Hence immediately postponing it on that.

With #2625152: Implement a Hierarchical Entity Processor and #2807333: Implement hierarchical structures in facets it becomes possible to store, and use hierarchy of fields to use in a facet. To work with fields across entity types, you need to combine the values into an aggregated field. The field has no metadata about type. So the hierarchy display is not available, even if you only combined say Taxonomy Term entities. Similarly for display this is not available for turning the ID into a translatabled entity name.

Comments

ekes created an issue. See original summary.

ekes’s picture

For those looking for a work around now:

Create an aggregated facet (first or union) that includes the Taxonomy Term field from the entity types.
Create a search_api processor that inherits the addHierarchy processor, but add you fields manually.


namespace Drupal\your_module\Plugin\search_api\processor;

use Drupal\search_api\Plugin\search_api\processor\AddHierarchy as SearchApiAddHierarchy;

/**
 * @SearchApiProcessor(
 *   id = "your_module_hierarchy",
 *   label = @Translation("Index hierarchy - Aggregated fields"),
 *   description = @Translation("Adds to hardcoded aggregated fields the indexing of values along with all their ancestors for hierarchical fields (like taxonomy term references)"),
 *   stages = {
 *     "preprocess_index" = -45
 *   }
 * )
 */
class AddHierarchy extends SearchApiAddHierarchy {

  /**
   * {@inheritdoc}
   */
  protected function getHierarchyFields() {
    // Array: index => field => hiearchy as $entityTypeId-$property.
    $fields = [
      'search_index_name' => [
        'aggregated_field_name' => ['taxonomy_term-parent' => 'Taxonomy term » Term Parents'],
      ],
    ];
    return $fields[$this->index->id()];
  }

}

Then to translate the ID to display I couldn't think of anything better than a cut & paste of facets TranslateEntityProcessor hard coding the entity type (Taxonomy term) that you put into the aggregated field.


namespace Drupal\your_module\Plugin\facets\processor;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\TypedData\TranslatableInterface;
use Drupal\facets\FacetInterface;
use Drupal\facets\Processor\BuildProcessorInterface;
use Drupal\facets\Processor\ProcessorPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Transforms the results to show the translated entity label.
 *
 * @FacetsProcessor(
 *   id = "translate_term_id",
 *   label = @Translation("Transform Term id into label"),
 *   description = @Translation("Show entity label instead of entity id. for an  integer known to be a Term ID."),
 *   stages = {
 *     "build" = 5
 *   }
 * )
 */
class TranslateTermIdProcessor 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;

  /**
   * Constructs a new 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.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, LanguageManagerInterface $language_manager, EntityTypeManagerInterface $entity_type_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);

    $this->languageManager = $language_manager;
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@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')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build(FacetInterface $facet, array $results) {
    $language_interface = $this->languageManager->getCurrentLanguage();

    $ids = [];

    /** @var \Drupal\facets\Result\ResultInterface $result */
    foreach ($results as $delta => $result) {
      $ids[$delta] = $result->getRawValue();
    }

    /** It's just this bit that has been changed **/
    // Default to nodes.
    $entity_type = 'taxonomy_term';
    /** Down to here **/

    // Load all indexed entities of this type.
    $entities = $this->entityTypeManager
      ->getStorage($entity_type)
      ->loadMultiple($ids);

    // Loop over all results.
    foreach ($results as $i => $result) {
      if (!isset($entities[$ids[$i]])) {
        unset($results[$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());
    }

    // Return the results with the new display values.
    return $results;
  }

}

Obviously this is going to fail if there are more than one entity type aggregated - but I can't think of a use case where that makes sense for hierarchy.

borisson_’s picture

Priority: Normal » Minor
Status: Postponed » Active

Making this active, because the original issue is now in. We're also adding our first test regarding aggregation as well in #2917323: Critical error thrown when editing a facet based on an aggregated field. But this can be worked on - if someone feels like a fun evening.

tsymi’s picture

Thanks a lot ! AddHierarchy processor gave on #2 works for me.