PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 1.10.2
Fluent Support – Helpdesk & Customer Support Ticket System v1.10.2
2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 All 68 releases
fluent-support / vendor / wpfluent / framework / src / WPFluent / Container / BoundMethod.php

BoundMethod.php in Fluent Support – Helpdesk & Customer Support Ticket System 1.10.2, at vendor/wpfluent/framework/src/WPFluent/Container/BoundMethod.php

210 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 FluentSupport\Framework\Container;
4
5 use Closure;
6 use ReflectionMethod;
7 use ReflectionFunction;
8 use InvalidArgumentException;
9 use FluentSupport\Framework\Database\Orm\Model;
10 use FluentSupport\Framework\Container\Contracts\BindingResolutionException;
11
12 class BoundMethod
13 {
14 /**
15 * Call the given Closure / class@method and inject its dependencies.
16 *
17 * @param \FluentSupport\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 \FluentSupport\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 \FluentSupport\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 \FluentSupport\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($container, $parameter, $parameters, $dependencies);
130 }
131
132 return array_merge($dependencies, array_values($parameters));
133 }
134
135 /**
136 * Get the proper reflection instance for the given callback.
137 *
138 * @param callable|string $callback
139 * @return \ReflectionFunctionAbstract
140 *
141 * @throws \ReflectionException
142 */
143 protected static function getCallReflector($callback)
144 {
145 if (is_string($callback) && strpos($callback, '::') !== false) {
146 $callback = explode('::', $callback);
147 } elseif (is_object($callback) && ! $callback instanceof Closure) {
148 $callback = [$callback, '__invoke'];
149 }
150
151 return is_array($callback)
152 ? new ReflectionMethod($callback[0], $callback[1])
153 : new ReflectionFunction($callback);
154 }
155
156 /**
157 * Get the dependency for the given call parameter.
158 *
159 * @param \FluentSupport\Framework\Container\Container $container
160 * @param \ReflectionParameter $parameter
161 * @param array $parameters
162 * @param array $dependencies
163 * @return void
164 *
165 * @throws \FluentSupport\Framework\Container\Contracts\BindingResolutionException
166 */
167 protected static function addDependencyForCallParameter($container, $parameter,
168 array &$parameters, &$dependencies)
169 {
170 if (array_key_exists($paramName = $parameter->getName(), $parameters)) {
171 $dependencies[] = $parameters[$paramName];
172
173 unset($parameters[$paramName]);
174 } elseif (! is_null($className = Util::getParameterClassName($parameter))) {
175 if (array_key_exists($className, $parameters)) {
176 $dependencies[] = $parameters[$className];
177
178 unset($parameters[$className]);
179 } else {
180 if ($parameter->isVariadic()) {
181 $variadicDependencies = $container->make($className);
182
183 $dependencies = array_merge($dependencies, is_array($variadicDependencies)
184 ? $variadicDependencies
185 : [$variadicDependencies]);
186 } else {
187 $dependencies[] = $container->make($className);
188 }
189 }
190 } elseif ($parameter->isDefaultValueAvailable()) {
191 $dependencies[] = $parameter->getDefaultValue();
192 } elseif (! $parameter->isOptional() && ! array_key_exists($paramName, $parameters)) {
193 $message = "Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}";
194
195 throw new BindingResolutionException($message);
196 }
197 }
198
199 /**
200 * Determine if the given string is in Class@method syntax.
201 *
202 * @param mixed $callback
203 * @return bool
204 */
205 protected static function isCallableWithAtSign($callback)
206 {
207 return is_string($callback) && strpos($callback, '@') !== false;
208 }
209 }
210