View source
<?php
declare (strict_types=1);
namespace Drupal\upgrade_status;
use Drupal\Core\Cache\NullBackend;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Theme\Registry;
use PhpParser\Error;
use PhpParser\Node;
use PhpParser\NodeFinder;
use PhpParser\ParserFactory;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Function_;
use Symfony\Component\DependencyInjection\ContainerInterface;
final class ThemeFunctionDeprecationAnalyzer {
private $container;
public function __construct(ContainerInterface $container) {
$this->container = $container;
}
public function analyze(Extension $extension) : array {
$deprecation_messages = [];
$deprecation_messages = array_merge($deprecation_messages, $this
->analyzeFunction($extension
->getName() . '_' . 'theme', $extension));
$deprecation_messages = array_merge($deprecation_messages, $this
->analyzeFunction($extension
->getName() . '_' . 'theme_registry_alter', $extension));
if ($extension
->getType() === 'theme') {
$theme_registry = new Registry($this->container
->get('app.root'), new NullBackend('null'), $this->container
->get('lock'), $this->container
->get('module_handler'), $this->container
->get('theme_handler'), $this->container
->get('theme.initialization'), $extension
->getName());
$theme_registry
->setThemeManager($this->container
->get('theme.manager'));
$theme_hooks = $theme_registry
->get();
$theme_function_overrides = drupal_find_theme_functions($theme_hooks, [
$extension
->getName(),
]);
foreach ($theme_function_overrides as $machine_name => $theme_function_override) {
try {
$function = new \ReflectionFunction($extension
->getName() . '_' . $machine_name);
$file = $function
->getFileName();
$line = $function
->getStartLine();
$deprecation_messages[$extension
->getName() . '_' . $machine_name] = new DeprecationMessage(sprintf('The theme is overriding the "%s" theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $machine_name), $file, $line);
} catch (\ReflectionException $e) {
}
}
}
return $deprecation_messages;
}
private function analyzeFunction(string $function, Extension $extension) : array {
$deprecation_messages = [];
try {
$function_reflection = new \ReflectionFunction($function);
} catch (\ReflectionException $e) {
return [];
}
$parser = (new ParserFactory())
->create(ParserFactory::PREFER_PHP7);
try {
$ast = $parser
->parse(file_get_contents($function_reflection
->getFileName()));
} catch (Error $error) {
$deprecation_messages[] = new DeprecationMessage(sprintf('Parse error while processing the %s hook implementation.', $theme_function), $function_reflection
->getFileName(), $node
->getStartLine());
}
if (!is_iterable($ast)) {
return [];
}
$finder = new NodeFinder();
$function_node = $finder
->findFirst($ast, function (Node $node) use ($function) {
return $node instanceof Function_ && isset($node->name) && $node->name->name === $function;
});
if (!$function_node) {
return [];
}
$theme_function_nodes = $finder
->find([
$function_node,
], function (Node $node) {
return $node instanceof ArrayItem && $node->key instanceof String_ && $node->key->value === 'function';
});
foreach ($theme_function_nodes as $node) {
$theme_function = $node->value instanceof String_ ? sprintf('"%s"', $node->value->value) : 'an unknown';
$deprecation_messages[] = new DeprecationMessage(sprintf('The %s is defining %s theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $extension
->getType(), $theme_function), $function_reflection
->getFileName(), $node
->getStartLine());
}
$theme_function_dim_nodes = $finder
->find([
$function_node,
], function (Node $node) {
return $node instanceof Assign && $node->var instanceof ArrayDimFetch && $node->var->dim instanceof String_ && $node->var->dim->value === 'function';
});
foreach ($theme_function_dim_nodes as $node) {
$theme_function = $node->expr instanceof String_ ? sprintf('"%s"', $node->expr->value) : 'an unknown';
$deprecation_messages[] = new DeprecationMessage(sprintf('The %s is defining %s theme function. Theme functions are deprecated. For more info, see https://www.drupal.org/node/2575445.', $extension
->getType(), $theme_function), $function_reflection
->getFileName(), $node
->getStartLine());
}
return $deprecation_messages;
}
}