From 4d99fcc687a31c4c10b681051080cadff2acb1fc Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Wed, 30 Nov 2022 00:36:03 -0400 Subject: [PATCH] Solr filter for entity relationship that has term. --- .../processor/EntityReferenceWithUri.php | 195 ++++++++++++++++++ .../EntityReferenceWithUriProperty.php | 62 ++++++ 2 files changed, 257 insertions(+) create mode 100644 src/Plugin/search_api/processor/EntityReferenceWithUri.php create mode 100644 src/Plugin/search_api/processor/Property/EntityReferenceWithUriProperty.php diff --git a/src/Plugin/search_api/processor/EntityReferenceWithUri.php b/src/Plugin/search_api/processor/EntityReferenceWithUri.php new file mode 100644 index 00000000..996c857d --- /dev/null +++ b/src/Plugin/search_api/processor/EntityReferenceWithUri.php @@ -0,0 +1,195 @@ +utils = $utils; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('islandora.utils'), + ); + } + + /** + * {@inheritdoc} + */ + public function getPropertyDefinitions(DatasourceInterface $datasource = NULL) { + $properties = []; + if (!$datasource || !$datasource->getEntityTypeId()) { + return $properties; + } + + $entity_type = $datasource->getEntityTypeId(); + + // Get all configured Entity Relation fields for this entity type. + $fields = \Drupal::entityTypeManager()->getStorage('field_config')->loadByProperties([ + 'entity_type' => $entity_type, + 'field_type' => 'entity_reference', + ]); + + foreach ($fields as $field) { + // Skip over fields that point to taxonomy term fields themselves. + if ($field->getSetting('target_type') == 'taxonomy_term') { + continue; + } + + $definition = [ + 'label' => $this->t('@label (by term URI) [@bundle]', [ + '@label' => $field->label(), + '@bundle' => $field->getTargetBundle(), + ]), + 'description' => $this->t('Index the target entity, but only if the target entity has a taxonomy term.'), + 'type' => 'string', + 'processor_id' => $this->getPluginId(), + 'settings' => [ + 'filter_terms' => [], + 'target_type' => $field->getSetting('target_type'), + ], + 'is_list' => TRUE, + ]; + $fieldname = 'entity_reference_with_term__' . str_replace('.', '__', $field->id()); + $properties[$fieldname] = new EntityReferenceWithUriProperty($definition); + } + return $properties; + } + + /** + * {@inheritdoc} + */ + public function addFieldValues(ItemInterface $item) { + // Skip if no Entity Reference with URI fields are configured. + $relevant_search_api_fields = []; + $search_api_fields = $item->getFields(FALSE); + foreach ($search_api_fields as $field) { + if (substr($field->getPropertyPath(), 0, 28) == 'entity_reference_with_term__') { + $relevant_search_api_fields[] = $field; + } + } + if (empty($relevant_search_api_fields)) { + return; + } + + $content_entity = $item->getOriginalObject()->getValue(); + $type_and_bundle_prefix = $content_entity->getEntityTypeId() . '__' . $content_entity->bundle() . '__'; + foreach ($relevant_search_api_fields as $search_api_field) { + $entity_type = $search_api_field->getConfiguration()['target_type']; + $filter_terms = $search_api_field->getConfiguration()['filter_terms']; + $filter_tids = array_map(function ($element) { + return $element['target_id']; + }, $filter_terms); + $require_all = $search_api_field->getConfiguration()['require_all']; + $field_name = substr($search_api_field->getPropertyPath(), 28); + $field_name = str_replace($type_and_bundle_prefix, '', $field_name); + if ($content_entity->hasField($field_name)) { + $referenced_terms = []; + foreach ($content_entity->get($field_name)->getValue() as $values) { + foreach ($values as $value) { + // Load the entity stored in our field. + $target_entity = \Drupal::entityTypeManager() + ->getStorage($entity_type) + ->load($value); + // Load the taxonomy terms on the entity stored in our field. + $referenced_terms = array_merge($referenced_terms, array_filter($target_entity->referencedEntities(), function ($entity) { + if ($entity->getEntityTypeId() != 'taxonomy_term') { + return FALSE; + } + else { + return TRUE; + } + })); + } + + $referenced_tids = array_map(function ($element) { + return $element->id(); + }, + $referenced_terms + ); + if ($require_all) { + if (count(array_intersect($referenced_tids, $filter_tids)) == count($filter_tids)) { + // "All" and all the terms specified are present. + $label = $target_entity->label(); + $search_api_field->addValue($label); + } + } + else { + if (count(array_intersect($referenced_tids, $filter_tids)) > 0) { + // "Any" and at least one term specified is present. + $label = $target_entity->label(); + $search_api_field->addValue($label); + } + } + } + } + } + } + + /** + * {@inheritdoc} + */ + public function requiresReindexing(array $old_settings = NULL, array $new_settings = NULL) { + if ($new_settings != $old_settings) { + return TRUE; + } + return FALSE; + } + +} diff --git a/src/Plugin/search_api/processor/Property/EntityReferenceWithUriProperty.php b/src/Plugin/search_api/processor/Property/EntityReferenceWithUriProperty.php new file mode 100644 index 00000000..3a084953 --- /dev/null +++ b/src/Plugin/search_api/processor/Property/EntityReferenceWithUriProperty.php @@ -0,0 +1,62 @@ + [], + 'require_all' => TRUE, + 'target_type' => '', + ]; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(FieldInterface $field, array $form, FormStateInterface $form_state) { + $configuration = $field->getConfiguration(); + $logger = \Drupal::logger('islandora'); + $logger->info('
' . print_r($configuration['filter_terms'], TRUE) . '
'); + $form['filter_terms'] = [ + '#type' => 'entity_autocomplete', + '#target_type' => 'taxonomy_term', + '#title' => $this->t('Related entities must have this URI to be included.'), + '#tags' => TRUE, + '#default_value' => array_map(function ($element) { + return Term::load($element['target_id']); + }, array_values($configuration['filter_terms'])), + '#required' => TRUE, + ]; + $form['require_all'] = [ + '#type' => 'checkbox', + '#title' => 'Require all terms', + '#description' => 'Only index related entities that have all the listed terms.', + '#default_value' => $configuration['require_all'], + ]; + // Store the target type of the field, it's a pain to get it when indexing. + $form['target_type'] = [ + '#type' => 'hidden', + '#value' => $field->getDataDefinition()->getSetting('target_type'), + ]; + return $form; + } + +}