PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.32
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.32
2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 1.45 All 41 releases
fluent-boards / vendor / wpfluent / framework / src / WPFluent / Container / BoundMethod.php

BoundMethod.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.32, at vendor/wpfluent/framework/src/WPFluent/Container/BoundMethod.php

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