diff --git a/token.tokens.inc b/token.tokens.inc index 4f519e7..15f1e76 100644 --- a/token.tokens.inc +++ b/token.tokens.inc @@ -5,6 +5,7 @@ * Token callbacks for the token module. */ use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Render\BubbleableMetadata; @@ -26,6 +27,7 @@ use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Entity\ContentEntityTypeInterface; + /** * Implements hook_token_info_alter(). */ @@ -1408,65 +1410,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 = $entity->$field_name; - $parts = explode(':', $name, 4); - $multivalued = false; - $delta = 0; - if ((count($parts) >= 3) && is_numeric($parts[1])) { - // Multivalued field. - $multivalued = true; - $delta = $parts[1]; - } - // Handle entity reference fields. - if ( - $field->getFieldDefinition()->getType() === 'entity_reference' - && (count($parts) > 2) - && !((count($parts) == 3) && $multivalued) - ) { - if ((count($parts) >= 4) && ($parts[2] === 'entity')) { - // Token is [entity:field_name:0:entity:value]. - if (count($field) <= $delta) { - // No such delta for this field, abort token replacement. - continue; - } - $literal_text = $parts[3]; - } - elseif (count($parts) >= 3 && ($parts[1] === 'entity')) { - // Token is [entity:field_name:entity:value]. - $literal_text = implode(':', array_slice($parts, 2)); - } - else { - // Token not of the form expected. - continue; - } - - // Get the referenced entity type. - $field_storage_definition = $field->getFieldDefinition()->getFieldStorageDefinition(); - $field_property_definition = $field_storage_definition->getPropertyDefinitions(); - $referenced_token_type = $field_property_definition['entity']->getTargetDefinition()->getEntityTypeId(); - - $field_name = \Drupal::service('token.entity_mapper')->getTokenTypeForEntityType($referenced_token_type, TRUE); - $referenced_entity = $field[$delta]->entity; - $bubbleable_metadata->addCacheableDependency($referenced_entity); - - $field_tokens = [ - $literal_text => $original, - ]; - $property_token_data = [ - $field_name => $referenced_entity, - ]; - } - // Handle fields that are not entity reference fields or field property - // tokens of entity reference fields (eg. [entity:field_name:entity] or - // [entity:field_name:0:entity]). - else { - $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, - ]; - } + $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); } @@ -1478,16 +1427,43 @@ function field_tokens($type, $tokens, array $data = array(), array $options = ar elseif (!empty($data['field_property'])) { foreach ($tokens as $name => $original) { // Handle [entity:field_name:0:value] tokens. + $filtered_tokens = $tokens; if (strpos($name, ':') !== FALSE) { list($delta, $rest) = explode(':', $name, 2); - $name = is_numeric($delta) ? $rest : $name; + if (is_numeric($delta)) { + $name = $rest; + // Pre-filter the tokens to select those with the correct delta. + $filtered_tokens = \Drupal::token()->findWithPrefix($tokens, $delta); + } + else { + $delta = 0; + } } // [entity:field_name:value] is treated as [entity:field_name:0:value]. else { $delta = 0; } - if (isset($data[$data['field_name']][$delta]) && isset($data[$data['field_name']][$delta]->$name)) { - $replacements[$original] = $data[$data['field_name']][$delta]->$name; + + if (isset($data[$data['field_name']][$delta])) { + $field_item = $data[$data['field_name']][$delta]; + } + else { + // The field has no such delta. + 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; + $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); + } + } + elseif (isset($field_item->$name)) { + $replacements[$original] = $field_item->$name; } } }