From c7fd8f89de9bc4f77e4bd89481e9fe3e7f972384 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Wed, 23 Nov 2022 16:40:03 -0400 Subject: [PATCH 1/8] Plugin for Filtered Typed Relation search. --- .../TypedRelationFilteredProperty.php | 44 ++++++++ .../processor/TypedRelationFiltered.php | 103 ++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php create mode 100644 src/Plugin/search_api/processor/TypedRelationFiltered.php diff --git a/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php new file mode 100644 index 0000000..78fb157 --- /dev/null +++ b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php @@ -0,0 +1,44 @@ + [], + ]; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(FieldInterface $field, array $form, FormStateInterface $form_state) { + $configuration = $field->getConfiguration(); + $form['rel_types'] = [ + '#type' => 'select', + '#title' => $this->t('Relations to include'), + '#options' => $field->getDataDefinition()->getSetting('options'), + '#multiple' => TRUE, + '#default_value' => $configuration['rel_types'], + '#required' => TRUE, + ]; + return $form; + } + +} \ No newline at end of file diff --git a/src/Plugin/search_api/processor/TypedRelationFiltered.php b/src/Plugin/search_api/processor/TypedRelationFiltered.php new file mode 100644 index 0000000..c90e1ff --- /dev/null +++ b/src/Plugin/search_api/processor/TypedRelationFiltered.php @@ -0,0 +1,103 @@ +getStorage('field_config')->loadByProperties(['field_type' => 'typed_relation']); + $properties = []; + foreach ($fields as $field) { + // Set a filtered field. + $definition = [ + 'label' => $this->t('@label (filtered by type) [@bundle]', [ + '@label' => $field->label(), + '@bundle' => $field->getTargetBundle(), + ]), + 'description' => $this->t('Typed relation field, filtered by type'), + 'type' => 'string', + 'processor_id' => $this->getPluginId(), + 'settings' => ['options' => $field->getSetting('rel_types')], + ]; + $fieldname = 'typed_relation_filter__' . str_replace('.','__', $field->id()); + $properties[$fieldname] = new TypedRelationFilteredProperty($definition); + $properties[$fieldname]->setSetting('options',$field->getSetting('rel_types') ); + } + return $properties; + } + + /** + * {@inheritdoc} + */ + public function addFieldValues(ItemInterface $item) { + // Skip if no Typed Relation Filtered search_api_fields are configured. + $skip = TRUE; + $search_api_fields = $item->getFields(FALSE); + foreach ($search_api_fields as $field) { + if (substr($field->getPropertyPath(), 0, 23) == 'typed_relation_filter__') { + $skip = FALSE; + } + } + if ($skip) { + return; + } + // Cycle over any typed relation fields on the original item. + $node = $item->getOriginalObject()->getValue(); + $field_defs = $node->getFieldDefinitions(); + foreach ($field_defs as $field) { + if ($field->getType() == 'typed_relation') { + $field_name = $field->getName(); + if (!$node->get($field_name)->isEmpty()) { + + // See if this field is being indexed. + $property_path = 'typed_relation_filter__' . str_replace('.','__', $field->id()); + $search_api_fields = $this->getFieldsHelper() + ->filterForPropertyPath($search_api_fields, NULL, $property_path); + + foreach ($search_api_fields as $search_api_field) { + + // Load field values. + $vals = $node->$field_name->getValue(); + foreach ($vals as $element) { + $rel_type = $element['rel_type']; + if (in_array($rel_type, $search_api_field->getConfiguration()['rel_types'])) { + $tid = $element['target_id']; + $taxo_term = \Drupal::entityTypeManager() + ->getStorage('taxonomy_term') + ->load($tid); + if ($taxo_term) { + $taxo_name = $taxo_term->name->value; + $search_api_field->addValue($taxo_name); + } + } + } + } + } + } + } + } + +} From 4b3ff5afab51e78bd55747b58403ec0743c0e31e Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Wed, 23 Nov 2022 17:30:14 -0400 Subject: [PATCH 2/8] Coding standards. --- .../processor/Property/TypedRelationFilteredProperty.php | 4 ++-- src/Plugin/search_api/processor/TypedRelationFiltered.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php index 78fb157..1666d86 100644 --- a/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php +++ b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php @@ -37,8 +37,8 @@ public function buildConfigurationForm(FieldInterface $field, array $form, FormS '#multiple' => TRUE, '#default_value' => $configuration['rel_types'], '#required' => TRUE, - ]; + ]; return $form; } -} \ No newline at end of file +} diff --git a/src/Plugin/search_api/processor/TypedRelationFiltered.php b/src/Plugin/search_api/processor/TypedRelationFiltered.php index c90e1ff..5302afa 100644 --- a/src/Plugin/search_api/processor/TypedRelationFiltered.php +++ b/src/Plugin/search_api/processor/TypedRelationFiltered.php @@ -27,7 +27,7 @@ class TypedRelationFiltered extends ProcessorPluginBase { * {@inheritdoc} */ public function getPropertyDefinitions(DatasourceInterface $datasource = NULL): array { - # Get all configured typed relation fields. + // Get all configured typed relation fields. $fields = \Drupal::entityTypeManager()->getStorage('field_config')->loadByProperties(['field_type' => 'typed_relation']); $properties = []; foreach ($fields as $field) { @@ -42,9 +42,9 @@ public function getPropertyDefinitions(DatasourceInterface $datasource = NULL): 'processor_id' => $this->getPluginId(), 'settings' => ['options' => $field->getSetting('rel_types')], ]; - $fieldname = 'typed_relation_filter__' . str_replace('.','__', $field->id()); + $fieldname = 'typed_relation_filter__' . str_replace('.', '__', $field->id()); $properties[$fieldname] = new TypedRelationFilteredProperty($definition); - $properties[$fieldname]->setSetting('options',$field->getSetting('rel_types') ); + $properties[$fieldname]->setSetting('options', $field->getSetting('rel_types')); } return $properties; } @@ -73,7 +73,7 @@ public function addFieldValues(ItemInterface $item) { if (!$node->get($field_name)->isEmpty()) { // See if this field is being indexed. - $property_path = 'typed_relation_filter__' . str_replace('.','__', $field->id()); + $property_path = 'typed_relation_filter__' . str_replace('.', '__', $field->id()); $search_api_fields = $this->getFieldsHelper() ->filterForPropertyPath($search_api_fields, NULL, $property_path); From 895e455501f831851c1534422178c484e95c711e Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Thu, 24 Nov 2022 09:56:57 -0400 Subject: [PATCH 3/8] Put in appropriate datasource. Make multivalued. --- .../processor/TypedRelationFiltered.php | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/Plugin/search_api/processor/TypedRelationFiltered.php b/src/Plugin/search_api/processor/TypedRelationFiltered.php index 5302afa..e8c14c7 100644 --- a/src/Plugin/search_api/processor/TypedRelationFiltered.php +++ b/src/Plugin/search_api/processor/TypedRelationFiltered.php @@ -27,11 +27,20 @@ class TypedRelationFiltered extends ProcessorPluginBase { * {@inheritdoc} */ public function getPropertyDefinitions(DatasourceInterface $datasource = NULL): array { - // Get all configured typed relation fields. - $fields = \Drupal::entityTypeManager()->getStorage('field_config')->loadByProperties(['field_type' => 'typed_relation']); $properties = []; + + if (!$datasource || !$datasource->getEntityTypeId()) { + return $properties; + } + + $entity_type = $datasource->getEntityTypeId(); + // Get all configured typed relation fields. + $fields = \Drupal::entityTypeManager()->getStorage('field_config')->loadByProperties([ + 'entity_type' => $entity_type, + 'field_type' => 'typed_relation', + ]); foreach ($fields as $field) { - // Set a filtered field. + // Create a "filtered" option. $definition = [ 'label' => $this->t('@label (filtered by type) [@bundle]', [ '@label' => $field->label(), @@ -40,11 +49,13 @@ public function getPropertyDefinitions(DatasourceInterface $datasource = NULL): 'description' => $this->t('Typed relation field, filtered by type'), 'type' => 'string', 'processor_id' => $this->getPluginId(), + 'is_list' => TRUE, 'settings' => ['options' => $field->getSetting('rel_types')], ]; $fieldname = 'typed_relation_filter__' . str_replace('.', '__', $field->id()); - $properties[$fieldname] = new TypedRelationFilteredProperty($definition); - $properties[$fieldname]->setSetting('options', $field->getSetting('rel_types')); + $property = new TypedRelationFilteredProperty($definition); + $property->setSetting('options', $field->getSetting('rel_types')); + $properties[$fieldname] = $property; } return $properties; } @@ -65,22 +76,19 @@ public function addFieldValues(ItemInterface $item) { return; } // Cycle over any typed relation fields on the original item. - $node = $item->getOriginalObject()->getValue(); - $field_defs = $node->getFieldDefinitions(); + $content_entity = $item->getOriginalObject()->getValue(); + $field_defs = $content_entity->getFieldDefinitions(); foreach ($field_defs as $field) { if ($field->getType() == 'typed_relation') { $field_name = $field->getName(); - if (!$node->get($field_name)->isEmpty()) { - + if (!$content_entity->get($field_name)->isEmpty()) { // See if this field is being indexed. $property_path = 'typed_relation_filter__' . str_replace('.', '__', $field->id()); $search_api_fields = $this->getFieldsHelper() - ->filterForPropertyPath($search_api_fields, NULL, $property_path); - + ->filterForPropertyPath($search_api_fields, $item->getDatasourceId(), $property_path); foreach ($search_api_fields as $search_api_field) { - - // Load field values. - $vals = $node->$field_name->getValue(); + // Load entity's field values. + $vals = $content_entity->$field_name->getValue(); foreach ($vals as $element) { $rel_type = $element['rel_type']; if (in_array($rel_type, $search_api_field->getConfiguration()['rel_types'])) { @@ -100,4 +108,14 @@ public function addFieldValues(ItemInterface $item) { } } + /** + * {@inheritdoc} + */ + public function requiresReindexing(array $old_settings = NULL, array $new_settings = NULL) { + if ($new_settings != $old_settings) { + return TRUE; + } + return FALSE; + } + } From 0e2e0b1bce980d5341ea8a817763cc1a4159ca5b Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Thu, 24 Nov 2022 14:30:00 -0400 Subject: [PATCH 4/8] Increase select box size. --- .../processor/Property/TypedRelationFilteredProperty.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php index 1666d86..e67a7a0 100644 --- a/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php +++ b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php @@ -37,6 +37,7 @@ public function buildConfigurationForm(FieldInterface $field, array $form, FormS '#multiple' => TRUE, '#default_value' => $configuration['rel_types'], '#required' => TRUE, + '#size' => 16, ]; return $form; } From f5843fa8705e2e628296bbd33759a155f75c2f0a Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Mon, 19 Dec 2022 14:01:06 -0400 Subject: [PATCH 5/8] DI etc. --- .../TypedRelationFilteredProperty.php | 8 ++ .../processor/TypedRelationFiltered.php | 114 +++++++++++++----- 2 files changed, 89 insertions(+), 33 deletions(-) diff --git a/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php index e67a7a0..86f4c4c 100644 --- a/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php +++ b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php @@ -39,6 +39,14 @@ public function buildConfigurationForm(FieldInterface $field, array $form, FormS '#required' => TRUE, '#size' => 16, ]; + $form['bundle'] = [ + '#type' => 'hidden', + '#value' => $field->getDataDefinition()->getSetting('bundle'), + ]; + $form['base_field'] = [ + '#type' => 'hidden', + '#value' => $field->getDataDefinition()->getSetting('base_field'), + ]; return $form; } diff --git a/src/Plugin/search_api/processor/TypedRelationFiltered.php b/src/Plugin/search_api/processor/TypedRelationFiltered.php index e8c14c7..55ff2f3 100644 --- a/src/Plugin/search_api/processor/TypedRelationFiltered.php +++ b/src/Plugin/search_api/processor/TypedRelationFiltered.php @@ -3,9 +3,11 @@ namespace Drupal\controlled_access_terms\Plugin\search_api\processor; use Drupal\controlled_access_terms\Plugin\search_api\processor\Property\TypedRelationFilteredProperty; +use Drupal\Core\Entity\EntityTypeManager; use Drupal\search_api\Datasource\DatasourceInterface; use Drupal\search_api\Item\ItemInterface; use Drupal\search_api\Processor\ProcessorPluginBase; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Adds filterable fields for each Typed Relation field. @@ -17,12 +19,56 @@ * stages = { * "add_properties" = 0, * }, - * locked = true, + * locked = false, * hidden = false, * ) */ class TypedRelationFiltered extends ProcessorPluginBase { + /** + * Entity Type Manager. + * + * @var \Drupal\Core\Entity\EntityTypeManager + */ + protected EntityTypeManager $entityTypeManager; + + /** + * Constructor. + * + * @param array $configuration + * The plugin configuration, i.e. an array with configuration values keyed + * by configuration option name. The special key 'context' may be used to + * initialize the defined contexts by setting it to an array of context + * values keyed by context names. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager + * The Entity Type Manager. + */ + public function __construct( + array $configuration, + $plugin_id, + $plugin_definition, + EntityTypeManager $entityTypeManager + ) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $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('entity_type.manager'), + ); + } + /** * {@inheritdoc} */ @@ -34,11 +80,13 @@ public function getPropertyDefinitions(DatasourceInterface $datasource = NULL): } $entity_type = $datasource->getEntityTypeId(); + // Get all configured typed relation fields. - $fields = \Drupal::entityTypeManager()->getStorage('field_config')->loadByProperties([ + $fields = $this->entityTypeManager->getStorage('field_config')->loadByProperties([ 'entity_type' => $entity_type, 'field_type' => 'typed_relation', ]); + foreach ($fields as $field) { // Create a "filtered" option. $definition = [ @@ -50,7 +98,11 @@ public function getPropertyDefinitions(DatasourceInterface $datasource = NULL): 'type' => 'string', 'processor_id' => $this->getPluginId(), 'is_list' => TRUE, - 'settings' => ['options' => $field->getSetting('rel_types')], + 'settings' => [ + 'options' => $field->getSetting('rel_types'), + 'bundle' => $field->getTargetBundle(), + 'base_field' => $field->getName(), + ], ]; $fieldname = 'typed_relation_filter__' . str_replace('.', '__', $field->id()); $property = new TypedRelationFilteredProperty($definition); @@ -65,43 +117,39 @@ public function getPropertyDefinitions(DatasourceInterface $datasource = NULL): */ public function addFieldValues(ItemInterface $item) { // Skip if no Typed Relation Filtered search_api_fields are configured. - $skip = TRUE; + $relevant_search_api_fields = []; $search_api_fields = $item->getFields(FALSE); - foreach ($search_api_fields as $field) { - if (substr($field->getPropertyPath(), 0, 23) == 'typed_relation_filter__') { - $skip = FALSE; + foreach ($search_api_fields as $search_api_field) { + if (substr($search_api_field->getPropertyPath(), 0, 23) == 'typed_relation_filter__') { + $relevant_search_api_fields[] = $search_api_field; } } - if ($skip) { + if (empty($search_api_fields)) { return; } // Cycle over any typed relation fields on the original item. $content_entity = $item->getOriginalObject()->getValue(); - $field_defs = $content_entity->getFieldDefinitions(); - foreach ($field_defs as $field) { - if ($field->getType() == 'typed_relation') { - $field_name = $field->getName(); - if (!$content_entity->get($field_name)->isEmpty()) { - // See if this field is being indexed. - $property_path = 'typed_relation_filter__' . str_replace('.', '__', $field->id()); - $search_api_fields = $this->getFieldsHelper() - ->filterForPropertyPath($search_api_fields, $item->getDatasourceId(), $property_path); - foreach ($search_api_fields as $search_api_field) { - // Load entity's field values. - $vals = $content_entity->$field_name->getValue(); - foreach ($vals as $element) { - $rel_type = $element['rel_type']; - if (in_array($rel_type, $search_api_field->getConfiguration()['rel_types'])) { - $tid = $element['target_id']; - $taxo_term = \Drupal::entityTypeManager() - ->getStorage('taxonomy_term') - ->load($tid); - if ($taxo_term) { - $taxo_name = $taxo_term->name->value; - $search_api_field->addValue($taxo_name); - } - } - } + + foreach ($relevant_search_api_fields as $search_api_field) { + $field_config = $search_api_field->getConfiguration(); + + // Exit if we're on the wrong bundle or the field isn't set. + if (($content_entity->bundle() != $field_config['bundle']) + || !$content_entity->hasField($field_config['base_field'])) { + return; + } + + $vals = $content_entity->$field_config['base_field']->getValue(); + foreach ($vals as $element) { + $rel_type = $element['rel_type']; + if (in_array($rel_type, $field_config['rel_types'])) { + $tid = $element['target_id']; + $taxo_term = $this->entityTypeManager + ->getStorage('taxonomy_term') + ->load($tid); + if ($taxo_term) { + $taxo_name = $taxo_term->name->value; + $search_api_field->addValue($taxo_name); } } } From a504ff8d6553c0f4184688a47f0db6a555015429 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Fri, 27 Jan 2023 14:38:35 -0400 Subject: [PATCH 6/8] Bugfix - typed relation search plugin. --- .../processor/Property/TypedRelationFilteredProperty.php | 2 ++ src/Plugin/search_api/processor/TypedRelationFiltered.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php index 86f4c4c..0d5938f 100644 --- a/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php +++ b/src/Plugin/search_api/processor/Property/TypedRelationFilteredProperty.php @@ -22,6 +22,8 @@ class TypedRelationFilteredProperty extends ConfigurablePropertyBase { public function defaultConfiguration() { return [ 'rel_types' => [], + 'bundle' => '', + 'base_field' => '', ]; } diff --git a/src/Plugin/search_api/processor/TypedRelationFiltered.php b/src/Plugin/search_api/processor/TypedRelationFiltered.php index 55ff2f3..1352051 100644 --- a/src/Plugin/search_api/processor/TypedRelationFiltered.php +++ b/src/Plugin/search_api/processor/TypedRelationFiltered.php @@ -139,7 +139,7 @@ public function addFieldValues(ItemInterface $item) { return; } - $vals = $content_entity->$field_config['base_field']->getValue(); + $vals = $content_entity->$field_config['base_field']; foreach ($vals as $element) { $rel_type = $element['rel_type']; if (in_array($rel_type, $field_config['rel_types'])) { From 20631f2fdb15b29a6488a2375ddfb7c748a747d1 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Fri, 27 Jan 2023 16:34:49 -0400 Subject: [PATCH 7/8] fix error causing no data to be indexed. --- src/Plugin/search_api/processor/TypedRelationFiltered.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugin/search_api/processor/TypedRelationFiltered.php b/src/Plugin/search_api/processor/TypedRelationFiltered.php index 1352051..74bc618 100644 --- a/src/Plugin/search_api/processor/TypedRelationFiltered.php +++ b/src/Plugin/search_api/processor/TypedRelationFiltered.php @@ -139,7 +139,7 @@ public function addFieldValues(ItemInterface $item) { return; } - $vals = $content_entity->$field_config['base_field']; + $vals = $content_entity->get($field_config['base_field'])->getValue; foreach ($vals as $element) { $rel_type = $element['rel_type']; if (in_array($rel_type, $field_config['rel_types'])) { From 2a8b7e86d717bd563432a7cfbc67e11cba82d103 Mon Sep 17 00:00:00 2001 From: Rosie Le Faive Date: Thu, 9 Feb 2023 16:47:47 -0400 Subject: [PATCH 8/8] Typo. --- src/Plugin/search_api/processor/TypedRelationFiltered.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugin/search_api/processor/TypedRelationFiltered.php b/src/Plugin/search_api/processor/TypedRelationFiltered.php index 74bc618..b28dbc1 100644 --- a/src/Plugin/search_api/processor/TypedRelationFiltered.php +++ b/src/Plugin/search_api/processor/TypedRelationFiltered.php @@ -139,7 +139,7 @@ public function addFieldValues(ItemInterface $item) { return; } - $vals = $content_entity->get($field_config['base_field'])->getValue; + $vals = $content_entity->get($field_config['base_field'])->getValue(); foreach ($vals as $element) { $rel_type = $element['rel_type']; if (in_array($rel_type, $field_config['rel_types'])) {