ArgumentsResolver.php

Same filename in other branches
  1. 9 core/lib/Drupal/Component/Utility/ArgumentsResolver.php
  2. 8.9.x core/lib/Drupal/Component/Utility/ArgumentsResolver.php
  3. 10 core/lib/Drupal/Component/Utility/ArgumentsResolver.php

Namespace

Drupal\Component\Utility

File

core/lib/Drupal/Component/Utility/ArgumentsResolver.php

View source
<?php

namespace Drupal\Component\Utility;


/**
 * Resolves the arguments to pass to a callable.
 */
class ArgumentsResolver implements ArgumentsResolverInterface {
    
    /**
     * An associative array of parameter names to scalar candidate values.
     *
     * @var array
     */
    protected $scalars;
    
    /**
     * An associative array of parameter names to object candidate values.
     *
     * @var array
     */
    protected $objects;
    
    /**
     * An array object candidates tried on every parameter regardless of name.
     *
     * @var array
     */
    protected $wildcards;
    
    /**
     * Constructs a new ArgumentsResolver.
     *
     * @param array $scalars
     *   An associative array of parameter names to scalar candidate values.
     * @param object[] $objects
     *   An associative array of parameter names to object candidate values.
     * @param object[] $wildcards
     *   An array object candidates tried on every parameter regardless of its
     *   name.
     */
    public function __construct(array $scalars, array $objects, array $wildcards) {
        $this->scalars = $scalars;
        $this->objects = $objects;
        $this->wildcards = $wildcards;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getArguments(callable $callable) {
        $arguments = [];
        foreach ($this->getReflector($callable)
            ->getParameters() as $parameter) {
            $arguments[] = $this->getArgument($parameter);
        }
        return $arguments;
    }
    
    /**
     * Gets the argument value for a parameter.
     *
     * @param \ReflectionParameter $parameter
     *   The parameter of a callable to get the value for.
     *
     * @return mixed
     *   The value of the requested parameter value.
     *
     * @throws \RuntimeException
     *   Thrown when there is a missing parameter.
     */
    protected function getArgument(\ReflectionParameter $parameter) {
        $parameter_type_hint = Reflection::getParameterClassName($parameter);
        $parameter_name = $parameter->getName();
        // If the argument exists and is NULL, return it, regardless of
        // parameter type hint.
        if (!isset($this->objects[$parameter_name]) && array_key_exists($parameter_name, $this->objects)) {
            return NULL;
        }
        if ($parameter_type_hint) {
            $parameter_type_hint = new \ReflectionClass($parameter_type_hint);
            // If the argument exists and complies with the type hint, return it.
            if (isset($this->objects[$parameter_name]) && is_object($this->objects[$parameter_name]) && $parameter_type_hint->isInstance($this->objects[$parameter_name])) {
                return $this->objects[$parameter_name];
            }
            // Otherwise, resolve wildcard arguments by type matching.
            foreach ($this->wildcards as $wildcard) {
                if ($parameter_type_hint->isInstance($wildcard)) {
                    return $wildcard;
                }
            }
        }
        elseif (isset($this->scalars[$parameter_name])) {
            return $this->scalars[$parameter_name];
        }
        // If the callable provides a default value, use it.
        if ($parameter->isDefaultValueAvailable()) {
            return $parameter->getDefaultValue();
        }
        // Can't resolve it: call a method that throws an exception or can be
        // overridden to do something else.
        return $this->handleUnresolvedArgument($parameter);
    }
    
    /**
     * Gets a reflector for the access check callable.
     *
     * The access checker may be either a procedural function (in which case the
     * callable is the function name) or a method (in which case the callable is
     * an array of the object and method name).
     *
     * @param callable $callable
     *   The callable (either a function or a method).
     *
     * @return \ReflectionFunctionAbstract
     *   The ReflectionMethod or ReflectionFunction to introspect the callable.
     */
    protected function getReflector(callable $callable) {
        if (is_array($callable)) {
            return new \ReflectionMethod($callable[0], $callable[1]);
        }
        if (is_string($callable) && str_contains($callable, "::")) {
            return \ReflectionMethod::createFromMethodName($callable);
        }
        return new \ReflectionFunction($callable);
    }
    
    /**
     * Handles unresolved arguments for getArgument().
     *
     * Subclasses that override this method may return a default value
     * instead of throwing an exception.
     *
     * @throws \RuntimeException
     *   Thrown when there is a missing parameter.
     */
    protected function handleUnresolvedArgument(\ReflectionParameter $parameter) {
        $class = $parameter->getDeclaringClass();
        $function = $parameter->getDeclaringFunction();
        if ($class && !$function->isClosure()) {
            $function_name = $class->getName() . '::' . $function->getName();
        }
        else {
            $function_name = $function->getName();
        }
        throw new \RuntimeException(sprintf('Callable "%s" requires a value for the "$%s" argument.', $function_name, $parameter->getName()));
    }

}

Classes

Title Deprecated Summary
ArgumentsResolver Resolves the arguments to pass to a callable.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.