function RenderCallbackRule::processNode
File
-
vendor/
mglaman/ phpstan-drupal/ src/ Rules/ Drupal/ RenderCallbackRule.php, line 69
Class
- RenderCallbackRule
- @implements Rule<Node\Expr\ArrayItem>
Namespace
mglaman\PHPStanDrupal\Rules\DrupalCode
public function processNode(Node $node, Scope $scope) : array {
$key = $node->key;
if (!$key instanceof Node\Scalar\String_) {
return [];
}
// @see https://www.drupal.org/node/2966725
$keySearch = array_search($key->value, $this->supportedKeys, true);
if ($keySearch === false) {
return [];
}
$keyChecked = $this->supportedKeys[$keySearch];
$value = $node->value;
if ($keyChecked === '#access_callback') {
return $this->doProcessNode($node->value, $scope, $keyChecked, 0);
}
if ($keyChecked === '#lazy_builder') {
if ($scope->isInClass()) {
$classReflection = $scope->getClassReflection();
$classType = new ObjectType($classReflection->getName());
// These classes use #lazy_builder in array_intersect_key. With
// PHPStan 1.6, nodes do not track their parent/next/prev which
// saves a lot of memory. But makes it harder to detect if we're
// in a call to array_intersect_key. This is an easier workaround.
$allowedTypes = new UnionType([
new ObjectType(PlaceholderGenerator::class),
new ObjectType(Renderer::class),
new ObjectType('Drupal\\Tests\\Core\\Render\\RendererPlaceholdersTest'),
]);
if ($allowedTypes->isSuperTypeOf($classType)
->yes()) {
return [];
}
}
if (!$value instanceof Node\Expr\Array_) {
return [
RuleErrorBuilder::message(sprintf('The "%s" expects a callable array with arguments.', $keyChecked))->line($node->getStartLine())
->build(),
];
}
if (count($value->items) === 0) {
return [];
}
// @todo take $value->items[1] and validate parameters against the callback.
return $this->doProcessNode($value->items[0]->value, $scope, $keyChecked, 0);
}
if (!$value instanceof Node\Expr\Array_) {
return [
RuleErrorBuilder::message(sprintf('The "%s" render array value expects an array of callbacks.', $keyChecked))->line($node->getStartLine())
->build(),
];
}
if (count($value->items) === 0) {
return [];
}
$errors = [];
foreach ($value->items as $pos => $item) {
$errors[] = $this->doProcessNode($item->value, $scope, $keyChecked, $pos);
}
return array_merge(...$errors);
}