PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.14
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.14
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / vendor / wpfluent / framework / src / WPFluent / Container / BoundMethod.php

BoundMethod.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.14, at vendor/wpfluent/framework/src/WPFluent/Container/BoundMethod.php

224 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\Framework\Container;
4
5 use Closure;
6 use ReflectionMethod;
7 use ReflectionFunction;
8 use InvalidArgumentException;
9 use FluentForm\Framework\Database\Orm\Model;
10 use FluentForm\Framework\Container\Contracts\BindingResolutionException;
11
12 class BoundMethod
13 {
14 /**
15 * Call the given Closure / class@method and inject its dependencies.
16 *
17 * @param \FluentForm\Framework\Container\Container $container
18 * @param callable|string $callback
19 * @param array $parameters
20 * @param string|null $defaultMethod
21 * @return mixed
22 *
23 * @throws \ReflectionException
24 * @throws \InvalidArgumentException
25 */
26 public static function call(
27 $container, $callback, array $parameters = [], $defaultMethod = null
28 )
29 {
30 if (
31 is_string($callback)
32 && ! $defaultMethod
33 && method_exists($callback, '__invoke')
34 ) {
35 $defaultMethod = '__invoke';
36 }
37
38 if (static::isCallableWithAtSign($callback) || $defaultMethod) {
39 return static::callClass(
40 $container, $callback, $parameters, $defaultMethod
41 );
42 }
43
44 return static::callBoundMethod($container, $callback, function () use ($container, $callback, $parameters) {
45 return $callback(
46 ...array_values(
47 static::getMethodDependencies(
48 $container, $callback, $parameters
49 )
50 )
51 );
52 });
53 }
54
55 /**
56 * Call a string reference to a class using Class@method syntax.
57 *
58 * @param \FluentForm\Framework\Container\Container $container
59 * @param string $target
60 * @param array $parameters
61 * @param string|null $defaultMethod
62 * @return mixed
63 *
64 * @throws \InvalidArgumentException
65 */
66 protected static function callClass(
67 $container, $target, array $parameters = [], $defaultMethod = null
68 )
69 {
70 $segments = explode('@', $target);
71
72 // We will assume an @ sign is used to delimit the class name from the method
73 // name. We will split on this @ sign and then build a callable array that
74 // we can pass right back into the "call" method for dependency binding.
75 $method = count($segments) === 2 ? $segments[1] : $defaultMethod;
76
77 if (is_null($method)) {
78 throw new InvalidArgumentException('Method not provided.');
79 }
80
81 return static::call(
82 $container, [$container->make($segments[0]), $method], $parameters
83 );
84 }
85
86 /**
87 * Call a method that has been bound to the container.
88 *
89 * @param \FluentForm\Framework\Container\Container $container
90 * @param callable $callback
91 * @param mixed $default
92 * @return mixed
93 */
94 protected static function callBoundMethod($container, $callback, $default)
95 {
96 if (! is_array($callback)) {
97 return Util::unwrapIfClosure($default);
98 }
99
100 // Here we need to turn the array callable into a Class@method string we can use to
101 // examine the container and see if there are any method bindings for this given
102 // method. If there are, we can call this method binding callback immediately.
103 $method = static::normalizeMethod($callback);
104
105 if ($container->hasMethodBinding($method)) {
106 return $container->callMethodBinding($method, $callback[0]);
107 }
108
109 return Util::unwrapIfClosure($default);
110 }
111
112 /**
113 * Normalize the given callback into a Class@method string.
114 *
115 * @param callable $callback
116 * @return string
117 */
118 protected static function normalizeMethod($callback)
119 {
120 $class = is_string($callback[0]) ? $callback[0] : get_class($callback[0]);
121
122 return "{$class}@{$callback[1]}";
123 }
124
125 /**
126 * Get all dependencies for a given method.
127 *
128 * @param \FluentForm\Framework\Container\Container $container
129 * @param callable|string $callback
130 * @param array $parameters
131 * @return array
132 *
133 * @throws \ReflectionException
134 */
135 protected static function getMethodDependencies($container, $callback, array $parameters = [])
136 {
137 $dependencies = [];
138
139 foreach (static::getCallReflector($callback)->getParameters() as $parameter) {
140 static::addDependencyForCallParameter(
141 $container, $parameter, $parameters, $dependencies
142 );
143 }
144
145 return array_merge($dependencies, array_values($parameters));
146 }
147
148 /**
149 * Get the proper reflection instance for the given callback.
150 *
151 * @param callable|string $callback
152 * @return \ReflectionFunctionAbstract
153 *
154 * @throws \ReflectionException
155 */
156 protected static function getCallReflector($callback)
157 {
158 if (is_string($callback) && strpos($callback, '::') !== false) {
159 $callback = explode('::', $callback);
160 } elseif (is_object($callback) && ! $callback instanceof Closure) {
161 $callback = [$callback, '__invoke'];
162 }
163
164 return is_array($callback)
165 ? new ReflectionMethod($callback[0], $callback[1])
166 : new ReflectionFunction($callback);
167 }
168
169 /**
170 * Get the dependency for the given call parameter.
171 *
172 * @param \FluentForm\Framework\Container\Container $container
173 * @param \ReflectionParameter $parameter
174 * @param array $parameters
175 * @param array $dependencies
176 * @return void
177 *
178 * @throws \FluentForm\Framework\Container\Contracts\BindingResolutionException
179 */
180 protected static function addDependencyForCallParameter(
181 $container, $parameter, array &$parameters, &$dependencies
182 )
183 {
184 if (array_key_exists($paramName = $parameter->getName(), $parameters)) {
185 $dependencies[] = $parameters[$paramName];
186
187 unset($parameters[$paramName]);
188 } elseif (! is_null($className = Util::getParameterClassName($parameter))) {
189 if (array_key_exists($className, $parameters)) {
190 $dependencies[] = $parameters[$className];
191
192 unset($parameters[$className]);
193 } else {
194 if ($parameter->isVariadic()) {
195 $variadicDependencies = $container->make($className);
196
197 $dependencies = array_merge($dependencies, is_array($variadicDependencies)
198 ? $variadicDependencies
199 : [$variadicDependencies]);
200 } else {
201 $dependencies[] = $container->make($className);
202 }
203 }
204 } elseif ($parameter->isDefaultValueAvailable()) {
205 $dependencies[] = $parameter->getDefaultValue();
206 } elseif (! $parameter->isOptional() && ! array_key_exists($paramName, $parameters)) {
207 $message = "Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}";
208
209 throw new BindingResolutionException($message);
210 }
211 }
212
213 /**
214 * Determine if the given string is in Class@method syntax.
215 *
216 * @param mixed $callback
217 * @return bool
218 */
219 protected static function isCallableWithAtSign($callback)
220 {
221 return is_string($callback) && strpos($callback, '@') !== false;
222 }
223 }
224