annotate core/lib/Drupal/Component/Utility/ArgumentsResolver.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Component\Utility;
Chris@0 4
Chris@0 5 /**
Chris@0 6 * Resolves the arguments to pass to a callable.
Chris@0 7 */
Chris@0 8 class ArgumentsResolver implements ArgumentsResolverInterface {
Chris@0 9
Chris@0 10 /**
Chris@0 11 * An associative array of parameter names to scalar candidate values.
Chris@0 12 *
Chris@0 13 * @var array
Chris@0 14 */
Chris@0 15 protected $scalars;
Chris@0 16
Chris@0 17 /**
Chris@0 18 * An associative array of parameter names to object candidate values.
Chris@0 19 *
Chris@0 20 * @var array
Chris@0 21 */
Chris@0 22 protected $objects;
Chris@0 23
Chris@0 24 /**
Chris@0 25 * An array object candidates tried on every parameter regardless of name.
Chris@0 26 *
Chris@0 27 * @var array
Chris@0 28 */
Chris@0 29 protected $wildcards;
Chris@0 30
Chris@0 31 /**
Chris@0 32 * Constructs a new ArgumentsResolver.
Chris@0 33 *
Chris@0 34 * @param array $scalars
Chris@0 35 * An associative array of parameter names to scalar candidate values.
Chris@0 36 * @param object[] $objects
Chris@0 37 * An associative array of parameter names to object candidate values.
Chris@0 38 * @param object[] $wildcards
Chris@0 39 * An array object candidates tried on every parameter regardless of its
Chris@0 40 * name.
Chris@0 41 */
Chris@0 42 public function __construct(array $scalars, array $objects, array $wildcards) {
Chris@0 43 $this->scalars = $scalars;
Chris@0 44 $this->objects = $objects;
Chris@0 45 $this->wildcards = $wildcards;
Chris@0 46 }
Chris@0 47
Chris@0 48 /**
Chris@0 49 * {@inheritdoc}
Chris@0 50 */
Chris@0 51 public function getArguments(callable $callable) {
Chris@0 52 $arguments = [];
Chris@0 53 foreach ($this->getReflector($callable)->getParameters() as $parameter) {
Chris@0 54 $arguments[] = $this->getArgument($parameter);
Chris@0 55 }
Chris@0 56 return $arguments;
Chris@0 57 }
Chris@0 58
Chris@0 59 /**
Chris@0 60 * Gets the argument value for a parameter.
Chris@0 61 *
Chris@0 62 * @param \ReflectionParameter $parameter
Chris@0 63 * The parameter of a callable to get the value for.
Chris@0 64 *
Chris@0 65 * @return mixed
Chris@0 66 * The value of the requested parameter value.
Chris@0 67 *
Chris@0 68 * @throws \RuntimeException
Chris@0 69 * Thrown when there is a missing parameter.
Chris@0 70 */
Chris@0 71 protected function getArgument(\ReflectionParameter $parameter) {
Chris@0 72 $parameter_type_hint = $parameter->getClass();
Chris@0 73 $parameter_name = $parameter->getName();
Chris@0 74
Chris@0 75 // If the argument exists and is NULL, return it, regardless of
Chris@0 76 // parameter type hint.
Chris@0 77 if (!isset($this->objects[$parameter_name]) && array_key_exists($parameter_name, $this->objects)) {
Chris@0 78 return NULL;
Chris@0 79 }
Chris@0 80
Chris@0 81 if ($parameter_type_hint) {
Chris@0 82 // If the argument exists and complies with the type hint, return it.
Chris@0 83 if (isset($this->objects[$parameter_name]) && is_object($this->objects[$parameter_name]) && $parameter_type_hint->isInstance($this->objects[$parameter_name])) {
Chris@0 84 return $this->objects[$parameter_name];
Chris@0 85 }
Chris@0 86 // Otherwise, resolve wildcard arguments by type matching.
Chris@0 87 foreach ($this->wildcards as $wildcard) {
Chris@0 88 if ($parameter_type_hint->isInstance($wildcard)) {
Chris@0 89 return $wildcard;
Chris@0 90 }
Chris@0 91 }
Chris@0 92 }
Chris@0 93 elseif (isset($this->scalars[$parameter_name])) {
Chris@0 94 return $this->scalars[$parameter_name];
Chris@0 95 }
Chris@0 96
Chris@0 97 // If the callable provides a default value, use it.
Chris@0 98 if ($parameter->isDefaultValueAvailable()) {
Chris@0 99 return $parameter->getDefaultValue();
Chris@0 100 }
Chris@0 101
Chris@0 102 // Can't resolve it: call a method that throws an exception or can be
Chris@0 103 // overridden to do something else.
Chris@0 104 return $this->handleUnresolvedArgument($parameter);
Chris@0 105 }
Chris@0 106
Chris@0 107 /**
Chris@0 108 * Gets a reflector for the access check callable.
Chris@0 109 *
Chris@0 110 * The access checker may be either a procedural function (in which case the
Chris@0 111 * callable is the function name) or a method (in which case the callable is
Chris@0 112 * an array of the object and method name).
Chris@0 113 *
Chris@0 114 * @param callable $callable
Chris@0 115 * The callable (either a function or a method).
Chris@0 116 *
Chris@0 117 * @return \ReflectionFunctionAbstract
Chris@0 118 * The ReflectionMethod or ReflectionFunction to introspect the callable.
Chris@0 119 */
Chris@0 120 protected function getReflector(callable $callable) {
Chris@0 121 return is_array($callable) ? new \ReflectionMethod($callable[0], $callable[1]) : new \ReflectionFunction($callable);
Chris@0 122 }
Chris@0 123
Chris@0 124 /**
Chris@0 125 * Handles unresolved arguments for getArgument().
Chris@0 126 *
Chris@0 127 * Subclasses that override this method may return a default value
Chris@0 128 * instead of throwing an exception.
Chris@0 129 *
Chris@0 130 * @throws \RuntimeException
Chris@0 131 * Thrown when there is a missing parameter.
Chris@0 132 */
Chris@0 133 protected function handleUnresolvedArgument(\ReflectionParameter $parameter) {
Chris@0 134 $class = $parameter->getDeclaringClass();
Chris@0 135 $function = $parameter->getDeclaringFunction();
Chris@0 136 if ($class && !$function->isClosure()) {
Chris@0 137 $function_name = $class->getName() . '::' . $function->getName();
Chris@0 138 }
Chris@0 139 else {
Chris@0 140 $function_name = $function->getName();
Chris@0 141 }
Chris@0 142 throw new \RuntimeException(sprintf('Callable "%s" requires a value for the "$%s" argument.', $function_name, $parameter->getName()));
Chris@0 143 }
Chris@0 144
Chris@0 145 }