diff --git a/tests/src/Kernel/FieldTest.php b/tests/src/Kernel/FieldTest.php index bb28dfd..795c8b5 100644 --- a/tests/src/Kernel/FieldTest.php +++ b/tests/src/Kernel/FieldTest.php @@ -125,7 +125,6 @@ class FieldTest extends KernelTestBase { 'bundle' => 'article', ])->save(); - // Add a node reference field. $this->createEntityReferenceField('node', 'article', 'test_reference', 'Test reference', 'node'); @@ -145,7 +144,7 @@ class FieldTest extends KernelTestBase { ] ); - // Add a field to the vocabulary. + // Add a field to terms of the created vocabulary. $storage = FieldStorageConfig::create([ 'field_name' => 'term_field', 'entity_type' => 'taxonomy_term', @@ -404,21 +403,20 @@ class FieldTest extends KernelTestBase { 'test_reference:target_id' => $reference->id(), 'test_term_reference:target_id' => $term_reference->id(), 'test_term_reference:entity:url:path' => '/' . $term_reference->toUrl('canonical')->getInternalPath(), + // Expects the entity's label to be returned for :entity tokens. + 'test_reference:entity' => $reference->label(), + 'test_term_reference:entity' => $term_reference->label(), ]); - // Test the :entity tokens. - $input = $this->mapTokenNames('node', ['test_term_reference:entity']); - $bubbleable_metadata = new BubbleableMetadata(); - $replacement = \Drupal::token()->generate('node', $input, ['node' => $entity], [], $bubbleable_metadata); - $replacement_term_field_value = $replacement['[node:test_term_reference:entity]']->get('term_field')->getValue()[0]['value']; - $this->assertTrue($replacement_term_field_value == $term_reference_field_value); - // Test some non existent tokens. $this->assertNoTokens('node', ['node' => $entity], [ 'test_reference:1:title', - 'test_term_reference:do_not_exists', - 'test_term_reference:do:not:exists', - 'test_term_reference:do_not_exists:0', + 'test_reference:entity:does_not_exist', + 'test_reference:does_not:exist', + 'test_term_reference:does_not_exist', + 'test_term_reference:does:not:exist', + 'test_term_reference:does_not_exist:0', + 'non_existing_field:entity:title', ]); } @@ -463,22 +461,23 @@ class FieldTest extends KernelTestBase { 'test_term_reference:0:target_id' => $terms[1]->id(), 'test_term_reference:1:target_id' => $terms[2]->id(), 'test_term_reference:2:target_id' => $terms[3]->id(), + // Expects the entity's label to be returned for :entity tokens. + 'test_term_reference:0:entity' => $terms[1]->label(), + 'test_term_reference:1:entity' => $terms[2]->label(), + 'test_term_reference:2:entity' => $terms[3]->label(), + // To make sure tokens without an explicit delta can also be replaced in + // the same token replacement call. + 'test_term_reference:entity:term_field' => Html::escape($terms[1]->term_field->value), + 'test_term_reference:target_id' => $terms[1]->id(), ]); // Test some non existent tokens. $this->assertNoTokens('node', ['node' => $entity], [ 'test_term_reference:3:term_field', - 'test_term_reference:0:do_not_exists', - 'test_term_reference:1:do:not:exists', - 'test_term_reference:1:2:do_not_exists', + 'test_term_reference:0:does_not_exist', + 'test_term_reference:1:does:not:exist', + 'test_term_reference:1:2:does_not_exist', ]); - - // Test the :entity tokens. - $input = $this->mapTokenNames('node', ['test_term_reference:0:entity']); - $bubbleable_metadata = new BubbleableMetadata(); - $replacement = \Drupal::token()->generate('node', $input, ['node' => $entity], [], $bubbleable_metadata); - $replacement_term_field_value = $replacement['[node:test_term_reference:0:entity]']->get('term_field')->getValue()[0]['value']; - $this->assertTrue($replacement_term_field_value == $terms_value[1]); } } diff --git a/token.tokens.inc b/token.tokens.inc index e0e4db7..564b22e 100644 --- a/token.tokens.inc +++ b/token.tokens.inc @@ -23,7 +23,6 @@ use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Entity\ContentEntityTypeInterface; - /** * Implements hook_token_info_alter(). */ @@ -1279,9 +1278,11 @@ function field_token_info_alter(&$info) { elseif (($property_definition instanceof DataReferenceDefinitionInterface) && ($property_definition->getTargetDefinition() instanceof EntityDataDefinitionInterface)) { $referenced_entity_type = $property_definition->getTargetDefinition()->getEntityTypeId(); $referenced_token_type = \Drupal::service('token.entity_mapper')->getTokenTypeForEntityType($referenced_entity_type); + $target_type_info = \Drupal::entityTypeManager()->getDefinition($referenced_entity_type); $info['tokens'][$field_token_name][$property] = [ 'name' => 'Referenced entity', - 'description' => t('The entity referenced by this entity reference field.'), + // Set the description as the label of the referenced entity. + 'description' => $target_type_info->getLabel(), 'module' => 'token', 'type' => $referenced_token_type, ]; @@ -1405,14 +1406,12 @@ function field_tokens($type, $tokens, array $data = array(), array $options = ar } // Handle [entity:field_name:value] and [entity:field_name:0:value] // tokens. - else { - $field_tokens = \Drupal::token()->findWithPrefix($tokens, $field_name); + else if ($field_tokens = \Drupal::token()->findWithPrefix($tokens, $field_name)) { $property_token_data = [ 'field_property' => TRUE, $data['entity_type'] . '-' . $field_name => $data['entity']->$field_name, 'field_name' => $data['entity_type'] . '-' . $field_name, ]; - $replacements += \Drupal::token()->generate($field_name, $field_tokens, $property_token_data, $options, $bubbleable_metadata); } } @@ -1421,45 +1420,49 @@ function field_tokens($type, $tokens, array $data = array(), array $options = ar unset($entity); } elseif (!empty($data['field_property'])) { - foreach ($tokens as $name => $original) { + foreach ($tokens as $token => $original) { $filtered_tokens = $tokens; - // Handle [entity:field_name:0:value] tokens. - if (strpos($name, ':') !== FALSE) { - list($delta, $rest) = explode(':', $name, 2); - if (is_numeric($delta)) { - $name = $rest; - // Pre-filter the tokens to select those with the correct delta. + $delta = 0; + $parts = explode(':', $token); + if (is_numeric($parts[0]) && (count($parts) > 1)) { + if (count($parts) > 1) { + $delta = $parts[0]; + $property_name = $parts[1]; $filtered_tokens = \Drupal::token()->findWithPrefix($tokens, $delta); + // Remove the delta to unify between having and not having one. + array_shift($parts); } else { - $delta = 0; + // Token is fieldname:delta, which is invalid. + continue; } } - // [entity:field_name:value] is treated as [entity:field_name:0:value]. else { - $delta = 0; + $property_name = $parts[0]; } if (isset($data[$data['field_name']][$delta])) { $field_item = $data[$data['field_name']][$delta]; } else { - // The field has no such delta. + // The field has no such delta, abort replacement. continue; } - if (strpos($name, ':') !== FALSE) { - list($property_name, $rest) = explode(':', $name, 2); - if (isset($field_item->$property_name) && ($field_item->$property_name instanceof FieldableEntityInterface)) { - // Entity reference field. - $entity = $field_item->$property_name; + if (isset($field_item->$property_name) && ($field_item->$property_name instanceof FieldableEntityInterface)) { + // Entity reference field. + $entity = $field_item->$property_name; + if (count($parts) > 1) { $field_tokens = \Drupal::token()->findWithPrefix($filtered_tokens, $property_name); $token_type = \Drupal::service('token.entity_mapper')->getTokenTypeForEntityType($entity->getEntityTypeId(), TRUE); $replacements += \Drupal::token()->generate($token_type, $field_tokens, [$token_type => $entity], $options, $bubbleable_metadata); } + else { + $replacements[$original] = $entity->label(); + } } - elseif (isset($field_item->$name)) { - $replacements[$original] = $field_item->$name; + else { + $replacements[$original] = $field_item->$property_name; } } }