Browse Source

Merge pull request #745 from dannylamb/node-has-term-or

Adding OR logic to NodeHasTerm and ilk
pull/752/head
Mark Jordan 5 years ago committed by GitHub
parent
commit
655f5013c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      config/schema/islandora.schema.yml
  2. 57
      src/IslandoraUtils.php
  3. 2
      src/Plugin/Condition/MediaHasTerm.php
  4. 64
      src/Plugin/Condition/NodeHasTerm.php
  5. 2
      src/Plugin/Condition/ParentNodeHasTerm.php
  6. 125
      src/Plugin/EntityReferenceSelection/ExternalUriSelection.php
  7. 26
      tests/src/Functional/NodeHasTermTest.php

9
config/schema/islandora.schema.yml

@ -78,6 +78,9 @@ condition.plugin.node_has_term:
uri: uri:
type: text type: text
label: 'Taxonomy Term URI' label: 'Taxonomy Term URI'
logic:
type: string
label: 'Logic (AND or OR)'
condition.plugin.node_has_parent: condition.plugin.node_has_parent:
type: condition.plugin type: condition.plugin
@ -95,6 +98,9 @@ condition.plugin.media_has_term:
uri: uri:
type: text type: text
label: 'Taxonomy Term URI' label: 'Taxonomy Term URI'
logic:
type: string
label: 'Logic (AND or OR)'
condition.plugin.parent_node_has_term: condition.plugin.parent_node_has_term:
type: condition.plugin type: condition.plugin
@ -102,6 +108,9 @@ condition.plugin.parent_node_has_term:
uri: uri:
type: text type: text
label: 'Taxonomy Term URI' label: 'Taxonomy Term URI'
logic:
type: string
label: 'Logic (AND or OR)'
condition.plugin.file_uses_filesystem: condition.plugin.file_uses_filesystem:
type: condition.plugin type: condition.plugin

57
src/IslandoraUtils.php

@ -235,12 +235,32 @@ class IslandoraUtils {
* Calling getStorage() throws if the storage handler couldn't be loaded. * Calling getStorage() throws if the storage handler couldn't be loaded.
*/ */
public function getTermForUri($uri) { public function getTermForUri($uri) {
$results = $this->entityQuery->get('taxonomy_term') // Get authority link fields to search.
->condition(self::EXTERNAL_URI_FIELD . '.uri', $uri) $field_map = $this->entityFieldManager->getFieldMap();
$fields = [];
foreach ($field_map['taxonomy_term'] as $field_name => $field_data) {
if ($field_data['type'] == 'authority_link') {
$fields[] = $field_name;
}
}
// Add field_external_uri.
$fields[] = self::EXTERNAL_URI_FIELD;
$query = $this->entityQuery->get('taxonomy_term');
$orGroup = $query->orConditionGroup();
foreach ($fields as $field) {
$orGroup->condition("$field.uri", $uri);
}
$results = $query
->condition($orGroup)
->execute(); ->execute();
if (empty($results)) { if (empty($results)) {
return NULL; return NULL;
} }
return $this->entityTypeManager->getStorage('taxonomy_term')->load(reset($results)); return $this->entityTypeManager->getStorage('taxonomy_term')->load(reset($results));
} }
@ -258,16 +278,39 @@ class IslandoraUtils {
* be created. * be created.
*/ */
public function getUriForTerm(TermInterface $term) { public function getUriForTerm(TermInterface $term) {
if ($term && $term->hasField(self::EXTERNAL_URI_FIELD)) { $fields = $this->getUriFieldNamesForTerms();
$field = $term->get(self::EXTERNAL_URI_FIELD); foreach ($fields as $field_name) {
if (!$field->isEmpty()) { if ($term && $term->hasField($field_name)) {
$link = $field->first()->getValue(); $field = $term->get($field_name);
return $link['uri']; if (!$field->isEmpty()) {
$link = $field->first()->getValue();
return $link['uri'];
}
} }
} }
return NULL; return NULL;
} }
/**
* Gets every field name that might contain an external uri for a term.
*
* @return string[]
* Field names for fields that a term may have as an external uri.
*/
public function getUriFieldNamesForTerms() {
// Get authority link fields to search.
$field_map = $this->entityFieldManager->getFieldMap();
$fields = [];
foreach ($field_map['taxonomy_term'] as $field_name => $field_data) {
if ($field_data['type'] == 'authority_link') {
$fields[] = $field_name;
}
}
// Add field_external_uri.
$fields[] = self::EXTERNAL_URI_FIELD;
return $fields;
}
/** /**
* Executes context reactions for a Node. * Executes context reactions for a Node.
* *

2
src/Plugin/Condition/MediaHasTerm.php

@ -7,7 +7,7 @@ namespace Drupal\islandora\Plugin\Condition;
* *
* @Condition( * @Condition(
* id = "media_has_term", * id = "media_has_term",
* label = @Translation("Media has term"), * label = @Translation("Media has term with URI"),
* context = { * context = {
* "media" = @ContextDefinition("entity:media", required = TRUE , label = @Translation("media")) * "media" = @ContextDefinition("entity:media", required = TRUE , label = @Translation("media"))
* } * }

64
src/Plugin/Condition/NodeHasTerm.php

@ -15,7 +15,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
* *
* @Condition( * @Condition(
* id = "node_has_term", * id = "node_has_term",
* label = @Translation("Node has term"), * label = @Translation("Node has term with URI"),
* context = { * context = {
* "node" = @ContextDefinition("entity:node", required = TRUE , label = @Translation("node")) * "node" = @ContextDefinition("entity:node", required = TRUE , label = @Translation("node"))
* } * }
@ -79,6 +79,16 @@ class NodeHasTerm extends ConditionPluginBase implements ContainerFactoryPluginI
); );
} }
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return array_merge(
['logic' => 'and'],
parent::defaultConfiguration()
);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -94,12 +104,24 @@ class NodeHasTerm extends ConditionPluginBase implements ContainerFactoryPluginI
$form['term'] = [ $form['term'] = [
'#type' => 'entity_autocomplete', '#type' => 'entity_autocomplete',
'#title' => $this->t('Term'), '#title' => $this->t('Term'),
'#description' => $this->t('Only terms that have external URIs/URLs will appear here.'),
'#tags' => TRUE, '#tags' => TRUE,
'#default_value' => $default, '#default_value' => $default,
'#target_type' => 'taxonomy_term', '#target_type' => 'taxonomy_term',
'#required' => TRUE, '#required' => TRUE,
'#selection_handler' => 'islandora:external_uri',
]; ];
$form['logic'] = [
'#type' => 'radios',
'#title' => $this->t('Logic'),
'#description' => $this->t('Whether to use AND or OR logic to evaluate multiple terms'),
'#options' => [
'and' => 'And',
'or' => 'Or',
],
'#default_value' => $this->configuration['logic'],
];
return parent::buildConfigurationForm($form, $form_state); return parent::buildConfigurationForm($form, $form_state);
} }
@ -124,6 +146,9 @@ class NodeHasTerm extends ConditionPluginBase implements ContainerFactoryPluginI
$this->configuration['uri'] = implode(',', $uris); $this->configuration['uri'] = implode(',', $uris);
} }
} }
$this->configuration['logic'] = $form_state->getValue('logic');
parent::submitConfigurationForm($form, $form_state); parent::submitConfigurationForm($form, $form_state);
} }
@ -153,22 +178,30 @@ class NodeHasTerm extends ConditionPluginBase implements ContainerFactoryPluginI
*/ */
protected function evaluateEntity(EntityInterface $entity) { protected function evaluateEntity(EntityInterface $entity) {
// Find the terms on the node. // Find the terms on the node.
$terms = array_filter($entity->referencedEntities(), function ($entity) { $field_names = $this->utils->getUriFieldNamesForTerms();
return $entity->getEntityTypeId() == 'taxonomy_term' && $terms = array_filter($entity->referencedEntities(), function ($entity) use ($field_names) {
$entity->hasField(IslandoraUtils::EXTERNAL_URI_FIELD) && if ($entity->getEntityTypeId() != 'taxonomy_term') {
!$entity->get(IslandoraUtils::EXTERNAL_URI_FIELD)->isEmpty(); return FALSE;
}
foreach ($field_names as $field_name) {
if ($entity->hasField($field_name) && !$entity->get($field_name)->isEmpty()) {
return TRUE;
}
}
return FALSE;
}); });
// Get their URIs. // Get their URIs.
$haystack = array_map(function ($term) { $haystack = array_map(function ($term) {
return $term->get(IslandoraUtils::EXTERNAL_URI_FIELD)->first()->getValue()['uri']; return $this->utils->getUriForTerm($term);
}, },
$terms $terms
); );
// FALSE if there's no URIs on the node. // FALSE if there's no URIs on the node.
if (empty($haystack)) { if (empty($haystack)) {
return $this->isNegated() ? TRUE : FALSE; return FALSE;
} }
// Get the URIs to look for. It's a required field, so there // Get the URIs to look for. It's a required field, so there
@ -176,12 +209,19 @@ class NodeHasTerm extends ConditionPluginBase implements ContainerFactoryPluginI
$needles = explode(',', $this->configuration['uri']); $needles = explode(',', $this->configuration['uri']);
// TRUE if every needle is in the haystack. // TRUE if every needle is in the haystack.
if (count(array_intersect($needles, $haystack)) == count($needles)) { if ($this->configuration['logic'] == 'and') {
return $this->isNegated() ? FALSE : TRUE; if (count(array_intersect($needles, $haystack)) == count($needles)) {
return TRUE;
}
return FALSE;
}
// TRUE if any needle is in the haystack.
else {
if (count(array_intersect($needles, $haystack)) > 0) {
return TRUE;
}
return FALSE;
} }
// Otherwise, FALSE.
return $this->isNegated() ? TRUE : FALSE;
} }
/** /**

2
src/Plugin/Condition/ParentNodeHasTerm.php

@ -7,7 +7,7 @@ namespace Drupal\islandora\Plugin\Condition;
* *
* @Condition( * @Condition(
* id = "parent_node_has_term", * id = "parent_node_has_term",
* label = @Translation("Parent node for media has term"), * label = @Translation("Parent node for media has term with URI"),
* context = { * context = {
* "media" = @ContextDefinition("entity:media", required = TRUE , label = @Translation("media")) * "media" = @ContextDefinition("entity:media", required = TRUE , label = @Translation("media"))
* } * }

125
src/Plugin/EntityReferenceSelection/ExternalUriSelection.php

@ -0,0 +1,125 @@
<?php
namespace Drupal\islandora\Plugin\EntityReferenceSelection;
use Drupal\taxonomy\Plugin\EntityReferenceSelection\TermSelection;
use Drupal\islandora\IslandoraUtils;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Filters by looking for entities with Authority Links or External Uris.
*
* @EntityReferenceSelection(
* id = "islandora:external_uri",
* label = @Translation("Taxonomy Term with external URI selection"),
* entity_types = {"taxonomy_term"},
* group = "islandora",
* weight = 1
* )
*/
class ExternalUriSelection extends TermSelection {
/**
* Islandora utils.
*
* @var \Drupal\islandora\IslandoraUtils
*/
protected $utils;
/**
* Constructs a new ExternalUriSelection 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\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity manager service.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
* @param \Drupal\Core\Session\AccountInterface $current_user
* The current user.
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
* The entity field manager.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
* The entity type bundle info service.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\islandora\IslandoraUtils $utils
* Islandora utils.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
EntityTypeManagerInterface $entity_type_manager,
ModuleHandlerInterface $module_handler,
AccountInterface $current_user,
EntityFieldManagerInterface $entity_field_manager = NULL,
EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL,
EntityRepositoryInterface $entity_repository = NULL,
IslandoraUtils $utils
) {
parent::__construct(
$configuration,
$plugin_id,
$plugin_definition,
$entity_type_manager,
$module_handler,
$current_user,
$entity_field_manager,
$entity_type_bundle_info,
$entity_repository
);
$this->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('entity_type.manager'),
$container->get('module_handler'),
$container->get('current_user'),
$container->get('entity_field.manager'),
$container->get('entity_type.bundle.info'),
$container->get('entity.repository'),
$container->get('islandora.utils')
);
}
/**
* {@inheritdoc}
*/
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
$options = parent::getReferenceableEntities($match, $match_operator, $limit);
foreach (array_keys($options) as $vid) {
foreach (array_keys($options[$vid]) as $tid) {
$term = $this->entityTypeManager->getStorage('taxonomy_term')->load($tid);
$uri = $this->utils->getUriForTerm($term);
if (empty($uri)) {
unset($options[$vid][$tid]);
}
}
if (empty($options[$vid])) {
unset($options[$vid]);
}
}
return $options;
}
}

26
tests/src/Functional/NodeHasTermTest.php

@ -77,14 +77,36 @@ class NodeHasTermTest extends IslandoraFunctionalTestBase {
$condition->setContextValue('node', $node); $condition->setContextValue('node', $node);
$this->assertFalse($condition->execute(), "Condition should fail if node does not have both terms"); $this->assertFalse($condition->execute(), "Condition should fail if node does not have both terms");
// Create a node with both tags. // Check for two tags this time.
// Node still only has one.
$condition = $condition_manager->createInstance(
'node_has_term',
[
'uri' => 'http://purl.org/coar/resource_type/c_c513,http://pcdm.org/use#PreservationMasterFile',
'logic' => 'or',
]
);
$condition->setContextValue('node', $node);
$this->assertTrue($condition->execute(), "Condition should pass if has one of two terms using OR logic.");
// Create a node with both tags and try it with OR.
$node = $this->container->get('entity_type.manager')->getStorage('node')->create([ $node = $this->container->get('entity_type.manager')->getStorage('node')->create([
'type' => 'test_type', 'type' => 'test_type',
'title' => 'Test Node', 'title' => 'Test Node',
'field_tags' => [$this->imageTerm->id(), $this->preservationMasterTerm->id()], 'field_tags' => [$this->imageTerm->id(), $this->preservationMasterTerm->id()],
]); ]);
$condition->setContextValue('node', $node); $condition->setContextValue('node', $node);
$this->assertTrue($condition->execute(), "Condition should pass if node has both terms"); $this->assertTrue($condition->execute(), "Condition should pass if node has both terms using OR logic");
// Try it with AND.
$condition = $condition_manager->createInstance(
'node_has_term',
[
'uri' => 'http://purl.org/coar/resource_type/c_c513,http://pcdm.org/use#PreservationMasterFile',
]
);
$condition->setContextValue('node', $node);
$this->assertTrue($condition->execute(), "Condition should pass if node has both terms using AND logic");
} }
} }

Loading…
Cancel
Save