Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. RenderCallbackRule.php

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\Drupal

Code

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);
}

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal