View source
<?php
namespace Drupal\api_tokens;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\RefinableCacheableDependencyTrait;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Render\RendererInterface;
use Drupal\Component\Serialization\Json;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
abstract class ApiTokenBase extends PluginBase implements ApiTokenPluginInterface {
use RefinableCacheableDependencyTrait;
protected $moduleHandler;
protected $renderer;
protected $logger;
protected $token;
protected $paramString;
protected $params;
protected $hash;
protected $reflector;
protected static $context = [];
public function __construct(array $configuration, $plugin_id, $plugin_definition, ModuleHandlerInterface $module_handler, RendererInterface $renderer, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->moduleHandler = $module_handler;
$this->renderer = $renderer;
$this->logger = $logger;
$this->paramString = isset($configuration['params']) ? $configuration['params'] : '';
$this->token = "[api:{$plugin_id}{$this->paramString}/]";
$this->params = $this->paramString ? Json::decode($this->paramString) : [];
$this->hash = $this->params ? hash('crc32b', serialize($this->params)) : '';
$this->reflector = method_exists($this, 'build') ? new \ReflectionMethod($this, 'build') : NULL;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('module_handler'), $container
->get('renderer'), $container
->get('logger.factory')
->get('api_tokens'));
}
public function id() {
return $this->pluginId;
}
public function label() {
return $this->pluginDefinition['label'];
}
public function description() {
return $this->pluginDefinition['description'];
}
public function provider() {
return $this->pluginDefinition['provider'];
}
public function token() {
return $this->token;
}
public function paramString() {
return $this->paramString;
}
public function params() {
return $this->params;
}
public function hash() {
return $this->hash;
}
public function reflector() {
return $this->reflector;
}
public function validateToken() {
if (!$this->reflector) {
$this->logger
->warning($this
->t('ApiToken plugin "@label" has no "build" method.', [
'@label' => $this
->label(),
]));
return FALSE;
}
if (!is_array($this->params)) {
$this->logger
->warning($this
->t('API token "@token" has invalid parameters format.', [
'@token' => $this->token,
]));
return FALSE;
}
if ($this->reflector
->getNumberOfRequiredParameters() > count($this->params)) {
$this->logger
->warning($this
->t('API token "@token" has not enough parameters.', [
'@token' => $this->token,
]));
return FALSE;
}
$params = [];
foreach ($this->reflector
->getParameters() as $index => $param) {
$use_default = $param
->isOptional() && !isset($this->params[$index]);
$params[$param
->getName()] = $use_default ? $param
->getDefaultValue() : $this->params[$index];
}
$provided_count = count($this->params);
$defined_count = count($params);
if ($provided_count > $defined_count) {
for ($index = $defined_count; $index < $provided_count; ++$index) {
$params[$index] = $this->params[$index];
}
}
if (!$this
->validate($params)) {
$this->logger
->warning($this
->t('API token "@token" has invalid parameters.', [
'@token' => $this->token,
]));
return FALSE;
}
return TRUE;
}
public function validate(array $params) {
return TRUE;
}
public function process() {
static $recursion = FALSE;
if ($recursion) {
return [];
}
$key = "{$this->pluginId}:{$this->hash}";
if (in_array($key, self::$context)) {
$recursion = TRUE;
$this->logger
->warning($this
->t('Recursion detected while rendering @token API token.', [
'@token' => $this->token,
]));
return [];
}
array_push(self::$context, $key);
$build = call_user_func_array([
$this,
'build',
], $this->params);
$this->moduleHandler
->alter('api_token_build', $build, $this);
$this->renderer
->renderPlain($build);
array_pop(self::$context);
if ($recursion) {
self::$context || ($recursion = FALSE);
return [];
}
$this
->addCacheableDependency(CacheableMetadata::createFromRenderArray($build));
$build = [
'#markup' => $build['#markup'],
'#attached' => $build['#attached'],
'#cache' => [
'contexts' => $this
->getCacheContexts(),
'tags' => $this
->getCacheTags(),
'max-age' => $this
->getCacheMaxAge(),
],
];
return $build;
}
public function fallback() {
return [];
}
public function placeholder() {
$placeholder = [
'#lazy_builder' => [
self::class . '::lazyBuilder',
[
$this->pluginId,
$this->paramString,
$this
->validateToken(),
],
],
'#cache' => [
'keys' => !self::$context ? [
'api_token',
$this->pluginId,
$this->hash,
] : NULL,
],
];
return $placeholder;
}
public static function lazyBuilder($id, $params, $valid) {
$plugin = \Drupal::service('plugin.manager.api_token')
->createInstance($id, [
'params' => $params,
]);
return $valid ? $plugin
->process() : $plugin
->fallback();
}
}