Problem/Motivation

  1. hook_token_info() is one of the last remaining info hooks in core.

  2. The Token API actively relies on hook_hook_info() to lazy-load token integration code from *.tokens.inc files on-demand only.

  3. hook_tokens() (a callback performing actual token replacements) is most often a big switch statement.

Proposed resolution

  1. This legacy construct can be cleanly replaced with plugins:

    1. Discovery
    2. Caching
    3. On-demand instantiation/processing
    4. Separate plugin methods for performing raw / sanitized replacements (security)

Remaining tasks

  • Convert all hook implementations to plugins.

User interface changes

None.

API changes

  1. A new plugin TokenType which has getInfo() and getTokens() methods to match existing hook_token_info and hook_tokens() methods. Implements a TokenTypeInterface
  2. The \Drupal\Core\Utility\Token class uses a TokenTypePluginBag to keep track of TokenType plugin instances.
  3. Replace calls to $this->moduleHandler->invokeAll('token_info') with calling methods on the plugins.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sun’s picture

Humm... adding another one... but FWIW, the full list of related issues pretty much is the list of open issues...

https://drupal.org/project/issues/drupal?version=8.x&component=token+system

I guess that only clarifies how broken the current token system is.

kim.pepper’s picture

Assigned: Unassigned » kim.pepper
kim.pepper’s picture

Status: Active » Needs review
FileSize
26.27 KB

Posted an inital patch to get the conversation going.

kim.pepper’s picture

Fixed a few obvious fatals.

The last submitted patch, 4: 2233353-token-plugins-4.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 5: 2233353-token-plugins-5.patch, failed testing.

kim.pepper’s picture

Status: Needs work » Needs review
FileSize
28.71 KB
3.85 KB

Using a plugin bag to instantiate all known plugins.

kim.pepper’s picture

Need to handle token_info as well. Fixes TokenTest too.

The last submitted patch, 8: 2233353-token-plugins-8.patch, failed testing.

The last submitted patch, 9: 2233353-token-plugins-9.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 9: 2233353-token-plugins-10.patch, failed testing.

kim.pepper’s picture

Issue summary: View changes
Berdir’s picture

Hm. I'm not too sure about this. Making it plugins like this seems very arbitrary. And it's very common for contrib to add more tokens so it's not quite clear to me if that would make sense then. We could possibly make the token types plugins, but we still need to define the info/metadata, and more closer to views_data and field definitions (which both *use* plugins but are not themself plugins) than something else. And sadly, I don't think we can still pull that off. We're done to *one* beta blocker and after that is done, we'll have two weeks to deal with beta targets and then it's over for 8.0.

Another problem in 8.x was that token API in 8.x saw _zero_ improvements, nobody was reviewing and RTBC'ing any of the various issues that for example tried to bring it closer to typed data (which would make more sense than to invent yet another data type system).

That said, 90%+ of the tokens are related to entities and fields. In #2326949-37: Move entity-type-specific schema information from the storage class to a schema handler, I had the idea that we could do the same as we already do for views_data and possibly soon for the sql schema there.

Meaning, we'd add a "token" entity handler that entity types can optionally provide. just like views_data, in a first step we can just move it and later on possibly think about an optional default implementation.

While the result will be similar to those first paches (a class per token type with the default tokens), it would feel more logical to me to provide an additional integration point for entities instead of replacing the info hook completely. For discovery, we'd go through all entity types with a token handler, and for generation, we can call that handler first and then the hook.

Thoughts?

kim.pepper’s picture

Hi Berdir,

Thanks for your detailed feedback.

I have to concede it's probably too late in the cycle to be messing with the token system, However, it think this is a pretty simple change, and bring tokens inline with the rest of D8 architecture.

Making it plugins like this seems very arbitrary. And it's very common for contrib to add more tokens so it's not quite clear to me if that would make sense then

We have hook_tokens_alter and hook_token_info alter still. This allows contrib to add more tokens. Is that not sufficient?

it would feel more logical to me to provide an additional integration point for entities instead of replacing the info hook completely.

I'm not across the work being done on entity handlers, so I can't really comment on that. However, wouldn't it make more sense to have a universal token solution, rather than an entity-specific one?

Anonymous’s picture

It would be interesting to have 1 token = 1 plugin. A lot of additional lines of code(ie. setting up new plugin class per token) but seems in line with what D8 is about. Shame it didn't made it to the core in time.

dawehner’s picture

That sounds more like a 9.0.x issue now?

dsnopek’s picture

Maybe it could still be done in a 8.x.0 point release, by adding the ability to declare tokens as plugins in addition to the hook?

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

cburschka’s picture

FileSize
30.79 KB

Tentatively reviving by forward-merging this patch across 3.5 years :D

However, I rather think that converting node.tokens.inc is premature for this issue. Maybe we can start by adding the plugin API, and leave core hook implementations to be converted in a follow-up?

andypost’s picture

geek-merlin’s picture

@cburschka: Cool you picked this up.

Looking into all of this, i feel i strongly agree though with some of the points @Berdir rose in #14:

> ... any of the various issues that for example tried to bring it closer to typed data (which would make more sense than to invent yet another data type system).

Strong +1... see some of the related issues.

> Meaning, we'd add a "token" entity handler that entity types can optionally provide. just like views_data, in a first step we can just move it and later on possibly think about an optional default implementation.

Makes sense to me. Maybe just typed data (as readonly-pseudofields).

So i'd rather unify tokens and typed data than bandaid tokens. And maybe this should mature in contrib first...
(I won't start this right now but feel free to ping me if someone does.)

kim.pepper’s picture

Assigned: kim.pepper » Unassigned

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

geek-merlin’s picture

kim.pepper’s picture

Version: 8.6.x-dev » 9.0.x-dev
Status: Needs work » Needs review
FileSize
26.85 KB

This is a deprecation, so won't get into 8.8.x or 8.9.x at this late stage.

Re-rolling for 9.0.x

kim.pepper’s picture

We're not quite ready to remove the hook_token_info implementations yet!

Status: Needs review » Needs work

The last submitted patch, 31: 2233353-31.patch, failed testing. View results

Berdir’s picture

I still don't think that this direction makes much sense, it moves the code into classes, but it doesn't really address any of the underlying issues with the token system.. that you have to manually traverse into nested tokens, re-defining all the things that already are defined as fields, ..

I'd much rather spend time on getting some if the improvements in token.module into core, like automatically generating tokens based on field definitions, as well as finding a way to remove the limit of only supporting a single data item per type. E.g. rules could never use the token system because you for example have the current and original node during an entity save hook.

Or alternatively, instead of injecting typed-data based information into the token system, we could possibly directly use it. ctools has a typed data traversal API that I'm also using in pathauto. See \Drupal\pathauto\Entity\PathautoPattern::getContexts(). We used to have a generic UI where you could add relationships and arbitrary conditions, but it was too complex to use for 90% of the use cases, so it's hidden away ;)

That would have the same issues as the serialization system though, that everything that you want to expose needs to be exposed as typed data, which is often awkward/slow, e.g. the long-standing issue of exposing image style URLs.

kim.pepper’s picture

OK fair enough. I'll leave this alone.

Are there any issues for automatically generating tokens off field definitions? Or if we are proposing we use typed data directly, we should probably have an issue in the ideas queue?

Berdir’s picture

If your goal is to move that code out of hooks into classes, then maybe the most straight-forward way to do so would be to try and get #2237831: Allow module services to specify hooks moving, based on the ideas from @catch, then you could just implemnt a a service for the token info + tokens hooks and use DI and so on without having to change anything about the token API.

Found these issues about the topics that I mentioned: #1222592: Architecture RFC: Field token architecture, #1920688: Support multiple instances of the same token type in token replacement and #1869582: Leverage the Typed Data API for token replacements

andypost’s picture

As I get the main question is does it makes sense to make field tokens with typed data or maybe better to propose token module to core?
Anyway it will be great to package remains of this hooks to plugins or tagged services to make faster at least

  1. +++ b/core/lib/Drupal/Core/Token/TokenTypeCollection.php
    @@ -0,0 +1,53 @@
    +    foreach ($this->definitions as $plugin_id => $definition) {
    +      if (!isset($this->pluginInstances[$plugin_id])) {
    +        $this->initializePlugin($plugin_id);
    ...
    +    $this->configurations[$instance_id] = $configuration;
    +    parent::initializePlugin($instance_id);
    
    +++ b/core/lib/Drupal/Core/Utility/Token.php
    @@ -374,7 +394,13 @@ public function getInfo() {
    +        foreach ($this->getTokenTypes() as $token_type) {
    +          $this->tokenInfo += $token_type->getTokenInfo();
    
    @@ -406,4 +432,18 @@ public function resetInfo() {
    +      $token_type_bag = new TokenTypeCollection($this->tokenTypeManager);
    +      $this->tokenTypes = $token_type_bag->getAll();
    

    Any reason to load all types all the time?
    I think it should use contexts like https://www.drupal.org/node/1938688

  2. +++ b/core/lib/Drupal/Core/Token/TokenTypeInterface.php
    @@ -0,0 +1,123 @@
    +   * @see hook_token_info()
    +   * @see hook_tokens_alter()
    
    +++ b/core/lib/Drupal/Core/Token/TokenTypeManager.php
    @@ -0,0 +1,31 @@
    +    $this->alterInfo('token_info');
    

    token(s)_info_alter could be painful for transition

geek-merlin’s picture

I fully support @berdir's reasoning in #33/#35. Let's put the effort into #1869582: Leverage the Typed Data API for token replacements instead!

kim.pepper’s picture

xjm’s picture

Version: 9.0.x-dev » 9.1.x-dev

This would be a minor-only change (with a new plugin API and deprecations of the old ones). Since 8.9.x and 9.0.x are now in beta, I'm moving this to 9.1.x. Thanks!

cyb_tachyon’s picture

To echo #36 , we need to ensure that the following systems interlink in a way that makes sense:

  • Typed Data API: Enables a system for retrieving, storing, and discovering Typed Data in Drupal
  • Context: Provides route, request, and build-specific Entities containing Typed Data to rendering systems
    • Plugins should have context provided by default on instantiation, and have that cleanly separated from context mapping and definitions
  • Token: Allows run-time replacement of strings with Entity values from arbitrary sources
    • The default Token Plugin Deriver should generate tokens based on Typed Data
    • The default arbitrary source for Token Entity values should be Context

That allows Plugins implementing token replacement to automatically have most of the work handled by the architecture of the system, instead of relying on a developer or end user to assign contexts to token types. It also would greatly reduce and simplify much of the context and token-related code in core.

This involves also touching the Plugin system, in addition to creating a TokenPluginManager and ecosystem.

geek-merlin’s picture

#40: Fully agree, thanks for elaborating. Is this a +1 for #37?

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.