token.api.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <?php
  2. /**
  3. * @file
  4. * Hooks related to the Token system.
  5. */
  6. use Drupal\user\Entity\User;
  7. /**
  8. * @addtogroup hooks
  9. * @{
  10. */
  11. /**
  12. * Provide replacement values for placeholder tokens.
  13. *
  14. * This hook is invoked when someone calls
  15. * \Drupal\Core\Utility\Token::replace(). That function first scans the text for
  16. * [type:token] patterns, and splits the needed tokens into groups by type.
  17. * Then hook_tokens() is invoked on each token-type group, allowing your module
  18. * to respond by providing replacement text for any of the tokens in the group
  19. * that your module knows how to process.
  20. *
  21. * A module implementing this hook should also implement hook_token_info() in
  22. * order to list its available tokens on editing screens.
  23. *
  24. * @param $type
  25. * The machine-readable name of the type (group) of token being replaced, such
  26. * as 'node', 'user', or another type defined by a hook_token_info()
  27. * implementation.
  28. * @param $tokens
  29. * An array of tokens to be replaced. The keys are the machine-readable token
  30. * names, and the values are the raw [type:token] strings that appeared in the
  31. * original text.
  32. * @param array $data
  33. * An associative array of data objects to be used when generating replacement
  34. * values, as supplied in the $data parameter to
  35. * \Drupal\Core\Utility\Token::replace().
  36. * @param array $options
  37. * An associative array of options for token replacement; see
  38. * \Drupal\Core\Utility\Token::replace() for possible values.
  39. * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata
  40. * The bubbleable metadata. Prior to invoking this hook,
  41. * \Drupal\Core\Utility\Token::generate() collects metadata for all of the
  42. * data objects in $data. For any data sources not in $data, but that are
  43. * used by the token replacement logic, such as global configuration (e.g.,
  44. * 'system.site') and related objects (e.g., $node->getOwner()),
  45. * implementations of this hook must add the corresponding metadata.
  46. * For example:
  47. * @code
  48. * $bubbleable_metadata->addCacheableDependency(\Drupal::config('system.site'));
  49. * $bubbleable_metadata->addCacheableDependency($node->getOwner());
  50. * @endcode
  51. *
  52. * Additionally, implementations of this hook, must forward
  53. * $bubbleable_metadata to the chained tokens that they invoke.
  54. * For example:
  55. * @code
  56. * if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) {
  57. * $replacements = $token_service->generate('date', $created_tokens, array('date' => $node->getCreatedTime()), $options, $bubbleable_metadata);
  58. * }
  59. * @endcode
  60. *
  61. * @return array
  62. * An associative array of replacement values, keyed by the raw [type:token]
  63. * strings from the original text. The returned values must be either plain
  64. * text strings, or an object implementing MarkupInterface if they are
  65. * HTML-formatted.
  66. *
  67. * @see hook_token_info()
  68. * @see hook_tokens_alter()
  69. */
  70. function hook_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
  71. $token_service = \Drupal::token();
  72. $url_options = ['absolute' => TRUE];
  73. if (isset($options['langcode'])) {
  74. $url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']);
  75. $langcode = $options['langcode'];
  76. }
  77. else {
  78. $langcode = NULL;
  79. }
  80. $replacements = [];
  81. if ($type == 'node' && !empty($data['node'])) {
  82. /** @var \Drupal\node\NodeInterface $node */
  83. $node = $data['node'];
  84. foreach ($tokens as $name => $original) {
  85. switch ($name) {
  86. // Simple key values on the node.
  87. case 'nid':
  88. $replacements[$original] = $node->nid;
  89. break;
  90. case 'title':
  91. $replacements[$original] = $node->getTitle();
  92. break;
  93. case 'edit-url':
  94. $replacements[$original] = $node->url('edit-form', $url_options);
  95. break;
  96. // Default values for the chained tokens handled below.
  97. case 'author':
  98. $account = $node->getOwner() ? $node->getOwner() : User::load(0);
  99. $replacements[$original] = $account->label();
  100. $bubbleable_metadata->addCacheableDependency($account);
  101. break;
  102. case 'created':
  103. $replacements[$original] = format_date($node->getCreatedTime(), 'medium', '', NULL, $langcode);
  104. break;
  105. }
  106. }
  107. if ($author_tokens = $token_service->findWithPrefix($tokens, 'author')) {
  108. $replacements += $token_service->generate('user', $author_tokens, ['user' => $node->getOwner()], $options, $bubbleable_metadata);
  109. }
  110. if ($created_tokens = $token_service->findWithPrefix($tokens, 'created')) {
  111. $replacements += $token_service->generate('date', $created_tokens, ['date' => $node->getCreatedTime()], $options, $bubbleable_metadata);
  112. }
  113. }
  114. return $replacements;
  115. }
  116. /**
  117. * Alter replacement values for placeholder tokens.
  118. *
  119. * @param $replacements
  120. * An associative array of replacements returned by hook_tokens().
  121. * @param $context
  122. * The context in which hook_tokens() was called. An associative array with
  123. * the following keys, which have the same meaning as the corresponding
  124. * parameters of hook_tokens():
  125. * - 'type'
  126. * - 'tokens'
  127. * - 'data'
  128. * - 'options'
  129. * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata
  130. * The bubbleable metadata. In case you alter an existing token based upon
  131. * a data source that isn't in $context['data'], you must add that
  132. * dependency to $bubbleable_metadata.
  133. *
  134. * @see hook_tokens()
  135. */
  136. function hook_tokens_alter(array &$replacements, array $context, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
  137. $options = $context['options'];
  138. if (isset($options['langcode'])) {
  139. $url_options['language'] = \Drupal::languageManager()->getLanguage($options['langcode']);
  140. $langcode = $options['langcode'];
  141. }
  142. else {
  143. $langcode = NULL;
  144. }
  145. if ($context['type'] == 'node' && !empty($context['data']['node'])) {
  146. $node = $context['data']['node'];
  147. // Alter the [node:title] token, and replace it with the rendered content
  148. // of a field (field_title).
  149. if (isset($context['tokens']['title'])) {
  150. $title = $node->field_title->view('default');
  151. $replacements[$context['tokens']['title']] = drupal_render($title);
  152. }
  153. }
  154. }
  155. /**
  156. * Provide information about available placeholder tokens and token types.
  157. *
  158. * Tokens are placeholders that can be put into text by using the syntax
  159. * [type:token], where type is the machine-readable name of a token type, and
  160. * token is the machine-readable name of a token within this group. This hook
  161. * provides a list of types and tokens to be displayed on text editing screens,
  162. * so that people editing text can see what their token options are.
  163. *
  164. * The actual token replacement is done by
  165. * \Drupal\Core\Utility\Token::replace(), which invokes hook_tokens(). Your
  166. * module will need to implement that hook in order to generate token
  167. * replacements from the tokens defined here.
  168. *
  169. * @return
  170. * An associative array of available tokens and token types. The outer array
  171. * has two components:
  172. * - types: An associative array of token types (groups). Each token type is
  173. * an associative array with the following components:
  174. * - name: The translated human-readable short name of the token type.
  175. * - description (optional): A translated longer description of the token
  176. * type.
  177. * - needs-data: The type of data that must be provided to
  178. * \Drupal\Core\Utility\Token::replace() in the $data argument (i.e., the
  179. * key name in $data) in order for tokens of this type to be used in the
  180. * $text being processed. For instance, if the token needs a node object,
  181. * 'needs-data' should be 'node', and to use this token in
  182. * \Drupal\Core\Utility\Token::replace(), the caller needs to supply a
  183. * node object as $data['node']. Some token data can also be supplied
  184. * indirectly; for instance, a node object in $data supplies a user object
  185. * (the author of the node), allowing user tokens to be used when only
  186. * a node data object is supplied.
  187. * - tokens: An associative array of tokens. The outer array is keyed by the
  188. * group name (the same key as in the types array). Within each group of
  189. * tokens, each token item is keyed by the machine name of the token, and
  190. * each token item has the following components:
  191. * - name: The translated human-readable short name of the token.
  192. * - description (optional): A translated longer description of the token.
  193. * - type (optional): A 'needs-data' data type supplied by this token, which
  194. * should match a 'needs-data' value from another token type. For example,
  195. * the node author token provides a user object, which can then be used
  196. * for token replacement data in \Drupal\Core\Utility\Token::replace()
  197. * without having to supply a separate user object.
  198. *
  199. * @see hook_token_info_alter()
  200. * @see hook_tokens()
  201. */
  202. function hook_token_info() {
  203. $type = [
  204. 'name' => t('Nodes'),
  205. 'description' => t('Tokens related to individual nodes.'),
  206. 'needs-data' => 'node',
  207. ];
  208. // Core tokens for nodes.
  209. $node['nid'] = [
  210. 'name' => t("Node ID"),
  211. 'description' => t("The unique ID of the node."),
  212. ];
  213. $node['title'] = [
  214. 'name' => t("Title"),
  215. ];
  216. $node['edit-url'] = [
  217. 'name' => t("Edit URL"),
  218. 'description' => t("The URL of the node's edit page."),
  219. ];
  220. // Chained tokens for nodes.
  221. $node['created'] = [
  222. 'name' => t("Date created"),
  223. 'type' => 'date',
  224. ];
  225. $node['author'] = [
  226. 'name' => t("Author"),
  227. 'type' => 'user',
  228. ];
  229. return [
  230. 'types' => ['node' => $type],
  231. 'tokens' => ['node' => $node],
  232. ];
  233. }
  234. /**
  235. * Alter the metadata about available placeholder tokens and token types.
  236. *
  237. * @param $data
  238. * The associative array of token definitions from hook_token_info().
  239. *
  240. * @see hook_token_info()
  241. */
  242. function hook_token_info_alter(&$data) {
  243. // Modify description of node tokens for our site.
  244. $data['tokens']['node']['nid'] = [
  245. 'name' => t("Node ID"),
  246. 'description' => t("The unique ID of the article."),
  247. ];
  248. $data['tokens']['node']['title'] = [
  249. 'name' => t("Title"),
  250. 'description' => t("The title of the article."),
  251. ];
  252. // Chained tokens for nodes.
  253. $data['tokens']['node']['created'] = [
  254. 'name' => t("Date created"),
  255. 'description' => t("The date the article was posted."),
  256. 'type' => 'date',
  257. ];
  258. }
  259. /**
  260. * @} End of "addtogroup hooks".
  261. */