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