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
Currently, using a token that refers to a field returns the content of the field using the default formatter of its field type, even if it's one of the field types that have a default_token_formatter value.
That's because D8 api evolved so hook_field_display_alter() does not exist anymore. See that change record.
Proposed resolution
Rewrite token_field_display_alter and change it to token_entity_view_display_alter.
Remaining tasks
Patch, Review, Commit.
User interface changes
Make that token default formatters work :)
API changes
None.
Data model changes
None.
Comment | File | Size | Author |
---|---|---|---|
#30 | token-fix_default_formatter-2603652-30.patch | 7.31 KB | hussainweb |
| |||
#30 | interdiff-28-30.txt | 2.93 KB | hussainweb |
Comments
Comment #2
DuaelFrComment #3
DuaelFrThat fix might depend on #2543756: Use renderPlain() in field_tokens()
Comment #5
DuaelFrI faced a case where $view_display was null so I just added a condition to avoid a fatal in this case.
Comment #7
DuaelFrIs the test suite up-to-date for 8.x?
Comment #8
couturier CreditAttribution: couturier as a volunteer commentedDuaelFr, yes I believe testing for 8.x is up to date: https://www.drupal.org/node/1319154#multiple-versions
Comment #9
BerdirTests pass again now.
This sounds like it might have some non-trivial runtime overhead. Maybe a better approach would be to provide a default view display for the token view mode and automatically configure it with the default formatter when a new field is added? Then it would be clear for a user what is actually used, unlike changing it at runtime in some magical way?
Or, we could check the existence of a token view display when actually viewing a token. And if we can't find it, just explicitly pass the default configuration/formatter to view() ?
Comment #10
hussainwebThis basically rerolls the patch in #5 and improves it a little bit. Basically, I remove the load() from inside the loop and replaced it with a loadMultiple(). I am not sure if it will address the runtime overhead concerns @Berdir raised in #9 but it should definitely help.
About the points in #9 itself:
This sounds good. I know we have another issue that really deals with that - #2430821: Token view modes are only created for entity types that exist when token is installed. However, it sounds to me that the first point is actually what happens now if the token view display is present and enabled.
Isn't this what we are doing here? The hook is called only when viewing the token, right?
Comment #11
hussainwebThis makes the hook even simpler. There is no need to load the view display when the current view display gives the information we need.
Comment #12
hussainwebThere are some other optimizations that can be done like removing getDefinition() from inside the loop but they are not that impactful. They just return cached data anyway. We are back at the question at what we really should do here.
Comment #13
BerdirKind of, yes. But we do it very indirectly, so when you look at the code that generates the token, it's hard to understand why the token looks the way it does. We can help with that by adding a simple @see in the code there.
Or we could do something like this:
Comment #14
hussainwebI see. Either way, it means that we will still need the hook we are working on at the moment, right? There isn't going to be any view display ready with all the formatters set to the default_token_formatter, which means we have to alter it in the entity_display_alter like we do in the patch. Is this a correct assessment?
Comment #15
Berdirview() accepts two argument types. A string, then it's a view mode and it will use the settings of that. Or, an array, then it's the formatter type + settings. It will create a runtime view display and work directly with those settings. We still need more or less the code from the hook but it wouldn't be a hook anymore, it would be a helper function/method that directly returns the array we need.
That has two advantages IMHO:
* The code flow is easier to understand
* We only need to get the information for the fields we are actually displaying. If you look at getSingleFieldDisplay(), we first get the full view display, alter all fields and then throw all non-matching ones out.
Comment #16
hussainwebThanks for the tips. The patch attached does that. Interdiff is missing because it mostly won't make sense at all as this is a very different change.
Comment #17
hussainwebRemoving the use statements from the token.module.
Comment #20
hussainwebI guess it is still moving:
Comment #22
hussainwebI will call it a day now and see if the CI issues have been resolved by morning.
Comment #23
hussainwebAll pass. Back to needs review.
Comment #24
Berdirthis conditional here can never be TRUE?
We should also make sure that the label is hidden. Needs to be on the same level as type I think, not inside settings.
Other than that, yes, I think its is easier to understand?
Lets wait with committing this for #2646316: Add tests for field tokens, then we can add test coverage.
Comment #25
hussainwebAh, that was left over from before when I was trying tertiary. Thanks, and fixed! I also set label to hidden. By default 'label' is set to 'above'.
About waiting for #2646316: Add tests for field tokens, the only change will be to remove the manual token block, right? I am not sure if that is enough. The patch here only makes sure the token view mode is used, if available. Otherwise default token formatter or default formatter is used. I don't think the patch is testing for any of these things. Besides, I think this also depends on what happens in #2430821: Token view modes are only created for entity types that exist when token is installed, which will decide how the view display will be created in the first place.
Comment #26
Berdir#2646316: Add tests for field tokens is in, lets improve the test coverage here.
I think we can test two things, which should test this sufficiently:
1. We remove the form display/view mode from where it is now. The test should then still pass as we should automatically use the default settings.
2. We re-add the view display later in the test and configure it explicitly to non-default settings (show the label, maybe use trimmed and only show a few characters, something like that. Then it should replace those explicit settings.
#2430821: Token view modes are only created for entity types that exist when token is installed shouldn't affect this. It's a kernel test, we already have to add the view mode by hand anyway.
Comment #27
hussainwebI am just checking for point 1 in the patch. Let's see what happens.
Comment #28
hussainwebAdding it in a new test method. This is somewhat similar to the existing
testEntityFieldTokens
method and I was considering putting it in there but I wanted to know your thoughts.Learnings while implementing it (possible bugs):
ContainerNotInitializedException
. I had to debug this in PHPUnit to figure it out. Even when the test was executing normally but there was only a slight difference in asserted values, I faced this seemingly weird error.The reason is that PHPUnit apparently serializes the object and sends it to stdout. The runner process takes this and unserializes it. In this case, the field token might be holding a reference to the entity, which when unserialized tries to get the container, which fails.
Comment #29
BerdirJust two tiny things then we should be good to go here.
Should we move the filter into setUp()? I don't think we'll need different filters...
A commit to explain this part would be great. Just that we explicitly create a token view display that should override the default configuration.
Comment #30
hussainwebI hope the comment is proper. I also added a comment explaining Unicode::check().
Comment #31
BerdirYeah, that's strange. Maybe open a core issue to do this by default? Surprised that nobody so far did run into this, I'd expect we have some Unicode:: calls in places that are often invoked?
Committed.