Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
For entity reference fields (and also timestamp fields), there exists more possibilities for tokens than the one configured using the token view mode.
For instance, given a field_sample_entity_reference
that points to another node, all fields, and node properties might be wanted as tokens (eg, [node:field_sample_entity_reference:title]
, node:field_sample_entity_reference:field_another_field
).
In Drupal 7, this was accomplished by the entity_token
sub-module of the Entity API module.
Proposed resolution
Support this here, or discuss and move back into the 8.x branch of the Entity API module.
Remaining tasks
- Integrate into the token browser
- Re-roll patch so it applies
- Tests
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#63 | chained_tokens_for-2493559-63-interdiff.txt | 4.46 KB | Berdir |
#63 | chained_tokens_for-2493559-63.patch | 13.27 KB | Berdir |
#62 | chained_tokens_for-2493559-62.patch | 11.89 KB | Bambell |
Comments
Comment #1
Maouna CreditAttribution: Maouna at bio.logis Genetic Information Management GmbH commentedComment #2
Maouna CreditAttribution: Maouna at bio.logis Genetic Information Management GmbH commentedComment #3
BerdirComment #4
Berdirmissing space before the =
This should be an elseif () and checking if there is a : on the token, or it might do weird stuff if it's another token.
You can also use something like this to avoid using the exploded value as an array:
list($field_name) = explode(':', $name);
You can simplify this a bit, make sure the field really exists with $entity->hasField() (or it will throw an exception if it doesn't) and then just do $entity->getFieldDefinition($field_name)->getFieldStorageDefinition(). That method works for base field definitions too, they are field definitions and field storage definitions and the method just returns themself again.
Comment #5
Maouna CreditAttribution: Maouna at bio.logis Genetic Information Management GmbH commentedI updated my patch. Thank you, Berdir, for your feedback which I tried to integrate.
Apart from that, I included the possibility to get the values from multiple fields, too. For example, if field_article_reference was a multiple field on node, referencing articles: [node:field_article_reference:1:title]
Also, the entities are now used in the translation selected in $options['langcode'].
Comment #6
Dave ReidSo now the hard part, is how do you expose all these additional tokens in the UI? Without that part, this cannot move forward.
Comment #7
Maouna CreditAttribution: Maouna at bio.logis Genetic Information Management GmbH commentedYes, providing the tokens in the token tree was a bit tricky. The updated patch is doing that now. Please have a look whether my approach is a good one or should be modified.
Comment #9
Maouna CreditAttribution: Maouna at bio.logis Genetic Information Management GmbH commentedComment #10
Maouna CreditAttribution: Maouna at bio.logis Genetic Information Management GmbH commentedI updated the patch. It includes now the bubbleable metadate of core.
Comment #13
juampynr CreditAttribution: juampynr at Lullabot commentedComment #14
jhedstromThis is what would provide support for things like
[node:field_my_entity_reference:title]
, yes?Unless I'm misunderstanding, this is at least a major.
Comment #15
BerdirThis is one related issue, yes. See also #2621598: Add support for field properties, which I think is more progressed and has info of the many hard problems here.
Also, for the record, token in 7.x never did this either, this was the entity tokens module, actually.
Not sure if we should close this as a duplicate, but it actually doesn't do the entity part yet, so maybe we could do that here then.
Comment #16
jhedstromUpdating the IS to reflect Berdir's feedback above.
Comment #17
jhedstromRe-roll of #10 to get this going again.
Comment #19
jhedstromThis fixes the failing tests. Working on adding some tests for the chained bit.
Comment #20
jhedstromThis adds tests for entity reference chaining.
Comment #21
scoff CreditAttribution: scoff commentedIt doesn't seem to work with taxonomy term fields. Works with Media (media_entity). Somewhat works with Paragraphs.
Am I missing something?
Comment #22
jhedstromThis adds a failing test for the taxonomy issue mentioned in #21. Not sure what the fix is just yet.
Comment #25
jhedstromI made a bit of progress in figuring out why certain types (taxonomy_term) aren't working.
It comes down to this bit of code in
token_tokens()
:Since
taxonomy_token_info()
doesn't use the actual entity id, butterm
instead, a mapping is needed. However, in this case, the$type
variable is set to the actual entity id (taxonomy_term
), so the reverse mapping would be needed. I don't think we can just check for both token-to-entity-type and entity-type-to-token here, so some other refactoring of this logic will be needed I think.Comment #26
jhedstromThe issue mentioned in #25 was actually related to this patch already, so the fix was to run entity types through the entity mapper service to convert them to token types prior to generating tokens. This also adds a test for cardinality > 1 chained tokens.
Comment #27
kevin.dutra CreditAttribution: kevin.dutra at Workday, Inc. commentedI've looked over #26 and things are looking pretty good. I only had time to do a small amount of manual testing, so if someone was able to do a bit more on that front, it would be good.
Comment #28
BerdirI'm not sure how this will work when combined with the field property patch.
That exposes things like test_reference:target_id and :entity.
And we can't do both at the same time.
So I still think we have to do that issue first, and then do something like test_reference:entity:title.
Comment #29
gappleTried this patch for use in a pathauto pattern, but validating the pattern fails because the numeric index is not understood in
Token::getInvalidTokens()
.I was able to get validation to pass by marking the 'multiple_field_{entity_type}' tokens as dynamic, but this caused the available tokens list to show the delta token as the child of a '?' placeholder instead of the field itself.
Comment #32
jhedstromThanks for the review @Berdir. I haven't had time to incorporate these changes, but just so this patch doesn't grow stale, here is a reroll against the latest 8.x. The tests are failing (as expected with the latest base field patch landing).
Comment #35
scoff CreditAttribution: scoff commentedI get an error "Field field_section:url:path is unknown." trying to save a node or running bulk update in Pathauto.
Using Tokens latest dev + 2493559-32.patch on Drupal 8.1.1
field_section is an Entity reference (Taxonomy term)
Pattern is /[node:field_section:url:path]/[node:nid]
The token is in the available tokens list under node:field_section as expected but none of node:field_section:* work (well, I haven't tried all of them) .
Comment #36
Berdir#2621598: Add support for field properties is in, so this will need a big reroll now.
With all the work that the other issue did, I would expect that this can now be done by building on top of that and just making sure the reference tokens are defined and passed along + test coverage.
Comment #37
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedI'll work on this today.
Edit : And tomorrow*.
Comment #38
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedRound 1.
I tried to re-use a maximum of code, but it was somewhat difficult to read and mostly no longer relevant with #2621598: Add support for field properties in. The logic is pretty straightforward. For single valued entity reference fields, if there is a token type defined for the referenced entity, field's token type is changed to that of the referenced entity. For multivalued fields, the list tokens are generated and it's the type of those that is changed. For fields token replacement, I add a check to verify if the field is an entity reference field. If so, I build the parameters needed for
\Drupal::token()->generate()
dependently of the field's cardinality, making sure only 1 token is passed togenerate()
. Some of that code could be taken form the previous patch.Comment #39
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedComment #40
BerdirI would expect that this now works on the field property level, just like entity field api.
Meaning, on an entity refrence field, I'd expect to see this:
[node:some_field:target_id] (already exists)
[node:some_field:entity] (added by this patch).
:entity is then the reference and of type term, for example.
Basically very similar to the image style patch
Comment #41
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedWe are loosing entity reference field property tokens with these patches (:target-id, :entity, etc.). The field's token type is changed to that of the referenced entity. As far as I can tell, there's 3 things we can do :
1- Add the field property tokens to the referenced entity's tokens (very bad).
2- Add the referenced entity's tokens to the entity reference field tokens (sounds like a bad idea).
3- Add instead an intermediary token to the entity reference field tokens that is of the referenced entity's type, so that we have :
[node:{entity_reference_field}:target_id]
[node:{entity_reference_field}:entity]
[node:{entity_reference_field}:referenced_entity:{referenced_entitys_tokens}]
I quickly started to implement the third option, but the problem comes with mutlivalued fields. Too many nested tokens, we cannot see the referenced entity's tokens in the tokens browser (see screenshot).
Not too sure which direction to go with this at this point.
Comment #42
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedWork in progress patch for 3., tests will fail.
Comment #45
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedHere we go, we now have those tokens :
The token replacement code isn't too elegant, though. Tried to keep it intelligible, but covering all cases is a bit complex.
Also added a basic test for
:entity
tokens. Interestingly, the replacement entity provided isn't identical to the referenced entity, it's missing fields and some values..Comment #46
jhedstromThis is looking pretty good! Thanks @Bambell for picking this up!
Comment #47
jhedstromCan the test be updated to demonstrate this issue?
Comment #48
jibranThere is a trait for this
EntityReferenceTestTrait
and all this can be replaced bycreateEntityReferenceField
Comment #49
larowlanthis breaks those of format
[entity:field_name:entity:url:path]
I think the == should be >=
Comment #50
larowlanWorking on fix
Comment #51
larowlanThis works, with a test to demonstrate
Comment #54
BerdirYou forgot a --relative :)
Comment #55
larowlanI ran --relative.
But I forgot to
cd
.Comment #56
jhedstromThis doesn't incorporate the test cleanup @jibran mentions in #48, but is looking good functionally.
Comment #57
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedImproving token replacement logic to make use of recursivity. Credits @Berdir for most of those changes ..!
Comment #58
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedAdding changes suggested in #48.
Comment #59
BerdirNice, getting close :)
Feedback on the test and another idea to simplify it a bit more:
The field is added to terms, not to the vocabulary. "to terms of the created vocabulary" maybe?
Lets add some bogus examples as well here, for fields/properties that don't exist.
so non_existing_field:entity:title should be empty, test_reference:foo:bar should be empty, and test_reference:entity:foo should be empty, all without errors.
Also mix in one example without an explicit delta as well, to make sure those can be mixed, even in the same token replace call.
unrelated change.
based on the target definition, we could actually display the label of the referenced entity here, check how \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::propertyDefinitions() does that.
revert those changes
Add a comment here, that the first part is not actually a delta, and we need to reset it to 0.
Actually, that makes me wonder if we can't improve this to only do a single explode.
Basically, that would look like this:
$delta = 0;
$parts = explode(':', $name); (maybe rename $name to $token in the foreach as well)
if (count($parts) == 1) {
// invalid token, ignore.
continue;
}
if (is_numeric($parts[0]) && count($parts) > 1) {
$delta = $parts[0];
$property_name = $parts[1];
$filtered_tokens = \Drupal::token()->findWithPrefix($tokens, $delta);
}
else {
$property_name = $parts[0];
}
// check if delta exists
...
if (property exists) {
$property_value = ...;
if ($property_value instanceof FieldableEntityInterface) {
// do entity stuff here
}
else {
// plain replacement here.
}
}
I think that would be more readable and easier to extend with e.g. the image style stuff as well.
Comment #60
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedRegarding 7., this won't work with
:entity
tokens (fieldname:delta:entity
orfieldname:entity
). It will try to generate tokens (it will get intoif ... instanceof FieldableEntityInterface
) while what we want is to directly provide a replacement.Comment #61
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedHere we go, all points have been addressed.
:entity
tokens are now being replaced by the referenced entity's label.Comment #62
Bambell CreditAttribution: Bambell at MD Systems GmbH commentedAdding a one line comment to clarify something.
Comment #63
BerdirSome final cleanups and also adding test coverage for the token info.
Comment #64
jhedstromThis looks good to go!
I manually tested too and verified this is behaving as expected in the UI.
Comment #66
BerdirThanks everyone!
Committed.
Comment #67
jibranNice work everyone. Great to see this patch is committed. @Berdir I hope this patch also works for DER field.
Comment #68
Berdir@jibran: I fear not, although it should support ERR. For DER, you'd need to have fake properties, one for each enabled target type to be able to expose that in a token compatible format in the token info. That said, replacements might actually work.
Comment #69
jibran@Berdir would you like to create an issue in DER issue queue with instructions to fix it?
Comment #71
nghai CreditAttribution: nghai at ]init[ AG commentedHi,
I have a query. Will this "Chained tokens" work only for Content entities reference fields which extended "\Drupal\Core\Entity\ContentEntityInterface" class not for other entities reference fields like Config entities which extended "\Drupal\Core\Config\Entity\ConfigEntityType")?
Why I am asking this because the node fields token replacement is not working for Domain entity reference fields?
If I am using this token [node:field_domain_access:0:entity:id] it results in a fatal error which states "Object of class Drupal\domain\Entity\Domain could not be converted to string in Drupal\Component\Render\HtmlEscapedText->__construct()" which is because this "field_token_info_alter" hook does not return any matching token info.