diff --git a/config/schema/islandora.schema.yml b/config/schema/islandora.schema.yml index 49de998b3..062bb78a2 100644 --- a/config/schema/islandora.schema.yml +++ b/config/schema/islandora.schema.yml @@ -231,6 +231,21 @@ reaction.plugin.delete: reaction.plugin.derivative: type: islandora.reaction.actions +search_api.property_configuration.entity_reference_with_term: + type: mapping + label: 'Entity reference filtered by term configuration' + mapping: + filter_terms: + type: sequence + label: 'Filter terms to find on related entities' + orderby: value + require_all: + type: boolean + label: 'Whether to require all terms, or any term.' + target_type: + type: string + label: 'The target entity type of this field.' + field.widget.settings.media_track: type: field.widget.settings.file_generic diff --git a/src/Plugin/search_api/processor/EntityReferenceWithUri.php b/src/Plugin/search_api/processor/EntityReferenceWithUri.php new file mode 100644 index 000000000..0867b19f8 --- /dev/null +++ b/src/Plugin/search_api/processor/EntityReferenceWithUri.php @@ -0,0 +1,216 @@ +utils = $utils; + $this->entityTypeManager = $entityTypeManager; + } + + /** + * {@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'), + $container->get('entity_type.manager'), + ); + } + + /** + * {@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 = $this->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 related 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. + try { + $target_entity = $this->entityTypeManager + ->getStorage($entity_type) + ->load($value); + } + catch (InvalidPluginDefinitionException $e) { + } + catch (PluginNotFoundException $e) { + } + // 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 000000000..5197fc94a --- /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' => $this->t('Require all terms'), + '#description' => $this->t('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; + } + +} 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 000000000..3a084953b --- /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; + } + +}