- Drupal 8 Module Development
- Daniel Sipos
- 661字
- 2021-07-02 15:45:22
Defining new tokens
We just saw how we can programmatically use existing tokens inside our strings and get them replaced with minimal effort. All we need is the token service and the data object that can be used to replace the token. Keep in mind that there are tokens which don't even require any data objects due to their global nature. The hook_tokens() implementation will take care of that--let's see how.
In the preceding chapter, we created functionalities for a dynamic "Hello World" message, which are either calculated or loaded from a configuration object. How about we expose the message to a token? This would make its usage more flexible because our string becomes exposed to the entire token system.
As mentioned, we will start with the hook_token_info() implementation:
/**
* Implements hook_token_info().
*/
function hello_world_token_info() {
$type = [
'name' => t('Hello World'),
'description' => t('Tokens related to the Hello World module.'),
];
$tokens['salutation'] = [
'name' => t('Salutation'),
'description' => t('The Hello World salutation value.'),
];
return [
'types' => ['hello_world' => $type],
'tokens' => ['hello_world' => $tokens],
];
}
In here, we will need to define two things--the types and the tokens. In our case, we are defining one of each. The type is hello_world and comes with a human-readable name and description in case it needs to be rendered somewhere in the UI. The token is salutation and belongs to the hello_world type. It also gets a name and description. At the end, we return an array that contains both.
What follows is the hook_tokens() implementation in which we handle the replacement of our token:
/**
* Implements hook_tokens().
*/
function hello_world_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
$replacements = [];
if ($type == 'hello_world') {
foreach ($tokens as $name => $original) {
switch ($name) {
case 'salutation':
$replacements[$original] = \Drupal::service('hello_world.salutation')->getSalutation();
$config = \Drupal::config('hello_world.custom_salutation');
$bubbleable_metadata->addCacheableDependency($config);
break;
}
}
}
return $replacements;
}
There is a bit more going on here, but I'll explain everything. This hook gets fired for each type located inside a string (after all have been scanned and grouped accordingly), and the $type is the first parameter. Inside $tokens, we get an array of tokens located in that string, which belong to the $type. The $data array contains the objects needed to replace the tokens, keyed by the type. This array can be empty (as it will be in our case).
Inside the function, we loop through each token of this group and try to replace it. We only know of one, and we use our HelloWorldSalutation service to determine the replacement string.
Finally, the function needs to return an array of all replacements found (which can be multiple if multiple tokens of the same type are found inside a string).
The bubbleable_metadata parameter is a special cache metadata object that describes this token in the cache system. It is needed because tokens get cached, so if any dependent object changes, the cache needs to be invalidated for this token as well. By default, all objects inside the $data array are read and included in this object. However, in our case, it is empty, yet we still depend on a configuration object that can change--the one that stores the overridden salutation message. So, we will need to add a dependency on that configuration object even if the actual value for the salutation we compute uses the same HelloWorldSalutation service we used before. So, we have a simple example here, but with a complex twist.
That's all there is to defining our token. It can now also be used inside strings and replaced using the Token service. Something like this:
$final_string = \Drupal::token()->replace('The salutation text is: [hello_world:salutation]');
As you can see, we pass no other parameters. If our token were dependent on an entity object, for example, we would have passed it in the second parameter array and would have made use of it inside hook_tokens() to compute the replacement.
- 黑客攻防從入門到精通(實戰秘笈版)
- Google Apps Script for Beginners
- Learning Apex Programming
- 自己動手實現Lua:虛擬機、編譯器和標準庫
- Python從菜鳥到高手(第2版)
- Java程序設計
- Windows內核編程
- 深入理解BootLoader
- TypeScript 2.x By Example
- Practical GIS
- 超好玩的Scratch 3.5少兒編程
- Functional Python Programming
- Neo4j權威指南 (圖數據庫技術叢書)
- Python AI游戲編程入門:基于Pygame和PyTorch
- Java Web程序員面試筆試寶典