diff -u b/tests/src/Kernel/FieldTest.php b/tests/src/Kernel/FieldTest.php --- b/tests/src/Kernel/FieldTest.php +++ b/tests/src/Kernel/FieldTest.php @@ -67,6 +67,22 @@ ]); $field->save(); + // Create a reference field with the same name on user. + $field_storage = FieldStorageConfig::create([ + 'field_name' => 'test_field', + 'entity_type' => 'user', + 'type' => 'reference', + ]); + $field_storage->save(); + + $field = FieldConfig::create([ + 'field_name' => 'test_field', + 'entity_type' => 'user', + 'bundle' => 'user', + 'label' => 'Test field', + ]); + $field->save(); + $this->testFormat = FilterFormat::create([ 'format' => 'test', 'weight' => 1, @@ -105,7 +121,11 @@ ]); $entity->save(); - $this->assertNoTokens('node', ['node' => $entity], ['test_field']); + $this->assertNoTokens('node', ['node' => $entity], [ + 'test_field', + 'test_field:value', + 'test_field:format', + ]); } /** diff -u b/token.tokens.inc b/token.tokens.inc --- b/token.tokens.inc +++ b/token.tokens.inc @@ -21,6 +21,7 @@ use Drupal\user\UserInterface; use Symfony\Cmf\Component\Routing\RouteObjectInterface; use Drupal\Core\TypedData\PrimitiveInterface; +use Drupal\Core\Field\FieldStorageDefinitionInterface; /** * Implements hook_token_info_alter(). @@ -1198,7 +1199,7 @@ } $cardinality = $field->getCardinality(); - $cardinality = ($cardinality < 0 || $cardinality > 3) ? 3 : $cardinality; + $cardinality = ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || $cardinality > 3) ? 3 : $cardinality; $field_token_name = $token_type . '-' . $field_name; $info['tokens'][$token_type][$field_name] = array( 'name' => SafeMarkup::checkPlain($label), @@ -1228,7 +1229,6 @@ for ($delta = 0; $delta <= $cardinality; $delta++) { $info['tokens']["list<$field_token_name>"][$delta] = [ 'name' => t('@type type with delta @delta', ['@type' => SafeMarkup::checkPlain($label), '@delta' => $delta]), - 'description' => t('The list item with delta @delta. Delta values start from 0 and are incremented by one per list item.', ['@delta' => $delta]), 'module' => 'token', 'type' => $field_token_name, ]; @@ -1239,8 +1239,8 @@ foreach ($field->getPropertyDefinitions() as $property => $property_definition) { if (is_subclass_of($property_definition->getClass(), 'Drupal\Core\TypedData\PrimitiveInterface')) { $info['tokens'][$field_token_name][$property] = [ - 'name' => (string) $property_definition->getLabel(), - 'description' => (string) $property_definition->getDescription(), + 'name' => $property_definition->getLabel(), + 'description' => $property_definition->getDescription(), 'module' => 'token', ]; } @@ -1302,74 +1302,91 @@ $token_view_display = (!empty($view_display) && $view_display->status()); /** @var \Drupal\Core\Field\FieldTypePluginManager $fieldTypeManager */ $fieldTypeManager = \Drupal::service('plugin.manager.field.field_type'); - foreach ($tokens as $name => $original) { - // Handle [entity:field_name:0] tokens. - list($field_name, $delta) = explode(':', $name, 2); - if (!is_numeric($delta)) { - unset($delta); + // For the [entity:field_name] token. + if (strpos($name, ':') === FALSE) { $field_name = $name; + $token_name = $name; } - // Replace the [entity:field-name] token only if token module added this - // token. - if ($entity->hasField($field_name) && _token_module($data['token_type'], $field_name) == 'token') { - // Do not continue if the field is empty or not a configurable field. - if ($entity->get($field_name)->isEmpty() || !($entity->getFieldDefinition($field_name) instanceof FieldConfigInterface)) { - continue; + // For [entity:field_name:0], [entity:field_name:0:value] and + // [entity:field_name:value] tokens. + else { + list($field_name, $delta) = explode(':', $name, 2); + if (!is_numeric($delta)) { + unset($delta); } + $token_name = $field_name; + } - $display_options = 'token'; - if (!$token_view_display) { - // We don't have the token view display and should fall back on - // default formatters. If the field has specified a specific formatter - // to be used by default with tokens, use that, otherwise use the - // default formatter. - $field_type_definition = $fieldTypeManager->getDefinition($entity->getFieldDefinition($field_name)->getType()); + // Replace the field token only if token module added this token. + if (_token_module($data['token_type'], $token_name) == 'token' ) { + // Handle [entity:field_name] and [entity:field_name:0] tokens. + if ($entity->hasField($field_name) && ($field_name === $name || isset($delta)) + && !($entity->get($field_name)->isEmpty()) && ($entity->getFieldDefinition($field_name) instanceof FieldConfigInterface)) { + $display_options = 'token'; + if (!$token_view_display) { + // We don't have the token view display and should fall back on + // default formatters. If the field has specified a specific formatter + // to be used by default with tokens, use that, otherwise use the + // default formatter. + $field_type_definition = $fieldTypeManager->getDefinition($entity->getFieldDefinition($field_name)->getType()); + $display_options = [ + 'type' => !empty($field_type_definition['default_token_formatter']) ? $field_type_definition['default_token_formatter'] : $field_type_definition['default_formatter'], + 'label' => 'hidden', + ]; + } - $display_options = [ - 'type' => !empty($field_type_definition['default_token_formatter']) ? $field_type_definition['default_token_formatter'] : $field_type_definition['default_formatter'], - 'label' => 'hidden', - ]; + // Render only one delta. + if (isset($delta)) { + if ($field_delta = $entity->{$field_name}[$delta]) { + $field_output = $field_delta->view($display_options); + } + // If no such delta exists, let's not replace the token. + else { + continue; + } + } + // Render the whole field (with all deltas). + else { + $field_output = $entity->$field_name->view($display_options); + // If we are displaying all field items we need this #pre_render + // callback. + $field_output['#pre_render'][] = 'token_pre_render_field_token'; + } + $field_output['#token_options'] = $options; + $replacements[$original] = \Drupal::service('renderer')->renderPlain($field_output); } - - $field_output = isset($delta) ? $entity->{$field_name}[$delta]->view($display_options) : $entity->$field_name->view($display_options); - $field_output['#token_options'] = $options; - // If we are displaying just one field item we don't need the - // #pre_render callback. - if (!isset($delta)) { - $field_output['#pre_render'][] = 'token_pre_render_field_token'; + // Handle [entity:field_name:value] and [entity:field_name:0:value] + // tokens. + else { + if ($field_tokens = \Drupal::token()->findWithPrefix($tokens, $field_name)) { + $property_token_data = [ + 'token_type' => 'field_property', + $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); + } } - $replacements[$original] = \Drupal::service('renderer')->renderPlain($field_output); - } - } - $fields = \Drupal::entityManager()->getFieldStorageDefinitions($data['entity_type']); - foreach ($fields as $field_name => $field) { - /** @var \Drupal\field\FieldStorageConfigInterface $field */ - if (!($field instanceof FieldStorageConfigInterface)) { - continue; - } - if ($field_tokens = \Drupal::token()->findWithPrefix($tokens, $field_name)) { - $data = [ - 'token_type' => 'field_property', - $data['entity_type'] . '-' . $field_name => $data['entity']->$field_name, - 'field_name' => $data['entity_type'] . '-' . $field_name, - ]; - - $replacements += \Drupal::token()->generate($field_name, $field_tokens, $data, $options, $bubbleable_metadata); } } - // Remove the cloned object from memory. unset($entity); } - elseif ($data['token_type'] == 'field_property') { + elseif (!empty($data['token_type']) && $data['token_type'] == 'field_property') { foreach ($tokens as $name => $original) { // Handle [entity:field_name:0:value] tokens. list($delta, $rest) = explode(':', $name, 2); $name = is_numeric($delta) ? $rest : $name; // [entity:field_name:value] is treated as [entity:field_name:0:value]. $delta = is_numeric($delta) ? $delta : 0; - $replacements[$original] = $data[$data['field_name']][$delta]->getValue()[$name]; + if ($field_delta = $data[$data['field_name']][$delta]) { + $replacements[$original] = $field_delta->getValue()[$name]; + } + // If no such delta exists, let's not replace the token. + else { + continue; + } } }