360ae351c059c0142053d6133585b1ce0147a826
[yaffs-website] / web / modules / contrib / token / src / Token.php
1 <?php
2
3 namespace Drupal\token;
4
5 use Drupal\Core\Cache\CacheBackendInterface;
6 use Drupal\Core\Language\LanguageInterface;
7 use Drupal\Core\Utility\Token as TokenBase;
8
9 /**
10  * Service to retrieve token information.
11  *
12  * This service replaces the core's token service and provides the same
13  * functionality by extending it. It also provides additional functionality
14  * commonly required by the additional support provided by token module and
15  * other modules.
16  */
17 class Token extends TokenBase implements TokenInterface {
18
19   /**
20    * Token definitions.
21    *
22    * @var array[]|null
23    *   An array of token definitions, or NULL when the definitions are not set.
24    *
25    * @see self::resetInfo()
26    */
27   protected $globalTokenTypes;
28
29   /**
30    * {@inheritdoc}
31    */
32   public function getInfo() {
33     if (empty($this->tokenInfo)) {
34       $cache_id = 'token_info_sorted:' . $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
35       $cache = $this->cache->get($cache_id);
36       if ($cache) {
37         $this->tokenInfo = $cache->data;
38       }
39       else {
40         $token_info = $this->moduleHandler->invokeAll('token_info');
41         $this->moduleHandler->alter('token_info', $token_info);
42
43         foreach (array_keys($token_info['types']) as $type_key) {
44           if (isset($token_info['types'][$type_key]['type'])) {
45             $base_type = $token_info['types'][$type_key]['type'];
46             // If this token type extends another token type, then merge in
47             // the base token type's tokens.
48             if (isset($token_info['tokens'][$base_type])) {
49               $token_info['tokens'] += [$type_key => []];
50               $token_info['tokens'][$type_key] += $token_info['tokens'][$base_type];
51             }
52           }
53           else {
54             // Add a 'type' value to each token type information.
55             $token_info['types'][$type_key]['type'] = $type_key;
56           }
57         }
58
59         // Pre-sort tokens.
60         $by_name = $this->prepareMultisort($token_info['types']);
61         array_multisort($by_name, SORT_ASC, SORT_NATURAL | SORT_FLAG_CASE, $token_info['types']);
62         foreach (array_keys($token_info['tokens']) as $type) {
63           $by_name = $this->prepareMultisort($token_info['tokens'][$type]);
64           array_multisort($by_name, SORT_ASC, SORT_NATURAL | SORT_FLAG_CASE, $token_info['tokens'][$type]);
65         }
66
67         $this->tokenInfo = $token_info;
68         $this->cache->set($cache_id, $this->tokenInfo, CacheBackendInterface::CACHE_PERMANENT, array(
69           static::TOKEN_INFO_CACHE_TAG,
70         ));
71       }
72     }
73
74     return $this->tokenInfo;
75   }
76
77   /**
78    * Extracts data from the token data for use in array_multisort().
79    *
80    * @param array $token_info
81    *   List of tokens or token types, each element must have a name key.
82    *
83    * @return string[]
84    *   List of the names keyed by the token key.
85    */
86   protected function prepareMultisort($token_info) {
87     $by_name = [];
88     foreach ($token_info as $key => $token_info_element) {
89       $by_name[$key] = $token_info_element['name'];
90     }
91     return $by_name;
92   }
93
94   /**
95    * {@inheritdoc}
96    */
97   public function getTokenInfo($token_type, $token) {
98     if (empty($this->tokenInfo)) {
99       $this->getInfo();
100     }
101
102     return isset($this->tokenInfo['tokens'][$token_type][$token]) ? $this->tokenInfo['tokens'][$token_type][$token] : NULL;
103   }
104
105   /**
106    * {@inheritdoc}
107    */
108   public function getTypeInfo($token_type) {
109     if (empty($this->tokenInfo)) {
110       $this->getInfo();
111     }
112
113     return isset($this->tokenInfo['types'][$token_type]) ? $this->tokenInfo['types'][$token_type] : NULL;
114   }
115
116   /**
117    * {@inheritdoc}
118    */
119   public function getGlobalTokenTypes() {
120     if (empty($this->globalTokenTypes)) {
121       $token_info = $this->getInfo();
122       foreach ($token_info['types'] as $type => $type_info) {
123         // If the token types has not specified that 'needs-data' => TRUE, then
124         // it is a global token type that will always be replaced in any context.
125         if (empty($type_info['needs-data'])) {
126           $this->globalTokenTypes[] = $type;
127         }
128       }
129     }
130
131     return $this->globalTokenTypes;
132   }
133
134   /**
135    * {@inheritdoc}
136    */
137   function getInvalidTokens($type, $tokens) {
138     $token_info = $this->getInfo();
139     $invalid_tokens = array();
140
141     foreach ($tokens as $token => $full_token) {
142       if (isset($token_info['tokens'][$type][$token])) {
143         continue;
144       }
145
146       // Split token up if it has chains.
147       $parts = explode(':', $token, 2);
148
149       if (!isset($token_info['tokens'][$type][$parts[0]])) {
150         // This is an invalid token (not defined).
151         $invalid_tokens[] = $full_token;
152       }
153       elseif (count($parts) == 2) {
154         $sub_token_info = $token_info['tokens'][$type][$parts[0]];
155         if (!empty($sub_token_info['dynamic'])) {
156           // If this token has been flagged as a dynamic token, skip it.
157           continue;
158         }
159         elseif (empty($sub_token_info['type'])) {
160           // If the token has chains, but does not support it, it is invalid.
161           $invalid_tokens[] = $full_token;
162         }
163         else {
164           // Recursively check the chained tokens.
165           $sub_tokens = $this->findWithPrefix(array($token => $full_token), $parts[0]);
166           $invalid_tokens = array_merge($invalid_tokens, $this->getInvalidTokens($sub_token_info['type'], $sub_tokens));
167         }
168       }
169     }
170
171     return $invalid_tokens;
172   }
173
174   /**
175    * {@inheritdoc}
176    */
177   public function getInvalidTokensByContext($value, array $valid_types = []) {
178     if (in_array('all', $valid_types)) {
179       $info = $this->getInfo();
180       $valid_types = array_keys($info['types']);
181     }
182     else {
183       // Add the token types that are always valid in global context.
184       $valid_types = array_merge($valid_types, $this->getGlobalTokenTypes());
185     }
186
187     $invalid_tokens = array();
188     $value_tokens = is_string($value) ? $this->scan($value) : $value;
189
190     foreach ($value_tokens as $type => $tokens) {
191       if (!in_array($type, $valid_types)) {
192         // If the token type is not a valid context, its tokens are invalid.
193         $invalid_tokens = array_merge($invalid_tokens, array_values($tokens));
194       }
195       else {
196         // Check each individual token for validity.
197         $invalid_tokens = array_merge($invalid_tokens, $this->getInvalidTokens($type, $tokens));
198       }
199     }
200
201     array_unique($invalid_tokens);
202     return $invalid_tokens;
203   }
204
205   /**
206    * {@inheritdoc}
207    */
208   public function resetInfo() {
209     parent::resetInfo();
210     $this->globalTokenTypes = NULL;
211   }
212
213 }