This repository has been archived on 2025-01-19. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
drupalcampbristol/web/modules/contrib/token/src/Token.php
2017-05-22 15:12:47 +01:00

213 lines
6.4 KiB
PHP

<?php
namespace Drupal\token;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Utility\Token as TokenBase;
/**
* Service to retrieve token information.
*
* This service replaces the core's token service and provides the same
* functionality by extending it. It also provides additional functionality
* commonly required by the additional support provided by token module and
* other modules.
*/
class Token extends TokenBase implements TokenInterface {
/**
* Token definitions.
*
* @var array[]|null
* An array of token definitions, or NULL when the definitions are not set.
*
* @see self::resetInfo()
*/
protected $globalTokenTypes;
/**
* {@inheritdoc}
*/
public function getInfo() {
if (empty($this->tokenInfo)) {
$cache_id = 'token_info_sorted:' . $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
$cache = $this->cache->get($cache_id);
if ($cache) {
$this->tokenInfo = $cache->data;
}
else {
$token_info = $this->moduleHandler->invokeAll('token_info');
$this->moduleHandler->alter('token_info', $token_info);
foreach (array_keys($token_info['types']) as $type_key) {
if (isset($token_info['types'][$type_key]['type'])) {
$base_type = $token_info['types'][$type_key]['type'];
// If this token type extends another token type, then merge in
// the base token type's tokens.
if (isset($token_info['tokens'][$base_type])) {
$token_info['tokens'] += [$type_key => []];
$token_info['tokens'][$type_key] += $token_info['tokens'][$base_type];
}
}
else {
// Add a 'type' value to each token type information.
$token_info['types'][$type_key]['type'] = $type_key;
}
}
// Pre-sort tokens.
$by_name = $this->prepareMultisort($token_info['types']);
array_multisort($by_name, SORT_ASC, SORT_NATURAL | SORT_FLAG_CASE, $token_info['types']);
foreach (array_keys($token_info['tokens']) as $type) {
$by_name = $this->prepareMultisort($token_info['tokens'][$type]);
array_multisort($by_name, SORT_ASC, SORT_NATURAL | SORT_FLAG_CASE, $token_info['tokens'][$type]);
}
$this->tokenInfo = $token_info;
$this->cache->set($cache_id, $this->tokenInfo, CacheBackendInterface::CACHE_PERMANENT, array(
static::TOKEN_INFO_CACHE_TAG,
));
}
}
return $this->tokenInfo;
}
/**
* Extracts data from the token data for use in array_multisort().
*
* @param array $token_info
* List of tokens or token types, each element must have a name key.
*
* @return string[]
* List of the names keyed by the token key.
*/
protected function prepareMultisort($token_info) {
$by_name = [];
foreach ($token_info as $key => $token_info_element) {
$by_name[$key] = $token_info_element['name'];
}
return $by_name;
}
/**
* {@inheritdoc}
*/
public function getTokenInfo($token_type, $token) {
if (empty($this->tokenInfo)) {
$this->getInfo();
}
return isset($this->tokenInfo['tokens'][$token_type][$token]) ? $this->tokenInfo['tokens'][$token_type][$token] : NULL;
}
/**
* {@inheritdoc}
*/
public function getTypeInfo($token_type) {
if (empty($this->tokenInfo)) {
$this->getInfo();
}
return isset($this->tokenInfo['types'][$token_type]) ? $this->tokenInfo['types'][$token_type] : NULL;
}
/**
* {@inheritdoc}
*/
public function getGlobalTokenTypes() {
if (empty($this->globalTokenTypes)) {
$token_info = $this->getInfo();
foreach ($token_info['types'] as $type => $type_info) {
// If the token types has not specified that 'needs-data' => TRUE, then
// it is a global token type that will always be replaced in any context.
if (empty($type_info['needs-data'])) {
$this->globalTokenTypes[] = $type;
}
}
}
return $this->globalTokenTypes;
}
/**
* {@inheritdoc}
*/
function getInvalidTokens($type, $tokens) {
$token_info = $this->getInfo();
$invalid_tokens = array();
foreach ($tokens as $token => $full_token) {
if (isset($token_info['tokens'][$type][$token])) {
continue;
}
// Split token up if it has chains.
$parts = explode(':', $token, 2);
if (!isset($token_info['tokens'][$type][$parts[0]])) {
// This is an invalid token (not defined).
$invalid_tokens[] = $full_token;
}
elseif (count($parts) == 2) {
$sub_token_info = $token_info['tokens'][$type][$parts[0]];
if (!empty($sub_token_info['dynamic'])) {
// If this token has been flagged as a dynamic token, skip it.
continue;
}
elseif (empty($sub_token_info['type'])) {
// If the token has chains, but does not support it, it is invalid.
$invalid_tokens[] = $full_token;
}
else {
// Recursively check the chained tokens.
$sub_tokens = $this->findWithPrefix(array($token => $full_token), $parts[0]);
$invalid_tokens = array_merge($invalid_tokens, $this->getInvalidTokens($sub_token_info['type'], $sub_tokens));
}
}
}
return $invalid_tokens;
}
/**
* {@inheritdoc}
*/
public function getInvalidTokensByContext($value, array $valid_types = []) {
if (in_array('all', $valid_types)) {
$info = $this->getInfo();
$valid_types = array_keys($info['types']);
}
else {
// Add the token types that are always valid in global context.
$valid_types = array_merge($valid_types, $this->getGlobalTokenTypes());
}
$invalid_tokens = array();
$value_tokens = is_string($value) ? $this->scan($value) : $value;
foreach ($value_tokens as $type => $tokens) {
if (!in_array($type, $valid_types)) {
// If the token type is not a valid context, its tokens are invalid.
$invalid_tokens = array_merge($invalid_tokens, array_values($tokens));
}
else {
// Check each individual token for validity.
$invalid_tokens = array_merge($invalid_tokens, $this->getInvalidTokens($type, $tokens));
}
}
array_unique($invalid_tokens);
return $invalid_tokens;
}
/**
* {@inheritdoc}
*/
public function resetInfo() {
parent::resetInfo();
$this->globalTokenTypes = NULL;
}
}