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