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