Passed
Push — main ( 9de461...110add )
by Andrey
01:31
created

Call::resolve()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
namespace Helldar\Support\Helpers;
4
5
use Closure;
6
use Helldar\Support\Facades\Helpers\Arr as ArrHelper;
7
use Helldar\Support\Facades\Helpers\Instance as InstanceHelper;
8
use Helldar\Support\Facades\Helpers\Is as IsHelper;
9
use Helldar\Support\Facades\Helpers\Reflection as ReflectionHelper;
10
use InvalidArgumentException;
11
use ReflectionClass;
12
13
final class Call
14
{
15
    /**
16
     * Gets the result of executing code in the specified class.
17
     *
18
     * @param  Closure|callable|string  $class
19
     * @param  string  $method
20
     * @param  mixed  ...$parameters
21
     *
22
     * @throws \ReflectionException
23
     *
24
     * @return mixed
25
     */
26 18
    public function run($class, string $method, ...$parameters)
27
    {
28 18
        $this->validate($class);
29
30 16
        if ($value = $this->callback($class, $method, ...$parameters)) {
31 4
            return $value;
32
        }
33
34 16
        $reflect = $this->reflection($class)->getMethod($method);
35
36 16
        if (! $reflect->isStatic() && ! InstanceHelper::of($class, Closure::class)) {
0 ignored issues
show
Bug introduced by
It seems like $class can also be of type callable; however, parameter $haystack of Helldar\Support\Facades\Helpers\Instance::of() does only seem to accept object|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

36
        if (! $reflect->isStatic() && ! InstanceHelper::of(/** @scrutinizer ignore-type */ $class, Closure::class)) {
Loading history...
37 16
            $class = $this->resolve($class);
38
        }
39
40 16
        return call_user_func([$class, $method], ...$parameters);
41
    }
42
43
    /**
44
     * Gets the result of executing code in the specified class if method exist.
45
     *
46
     * @param  Closure|callable|string  $class
47
     * @param  string  $method
48
     * @param  mixed  ...$parameters
49
     *
50
     * @throws \ReflectionException
51
     *
52
     * @return mixed
53
     */
54 12
    public function runExists($class, string $method, ...$parameters)
55
    {
56 12
        $this->validate($class);
57
58 12
        if ($value = $this->callback($class, $method, ...$parameters)) {
59 2
            return $value;
60
        }
61
62 12
        if (method_exists($class, $method)) {
63 12
            return $this->run($class, $method, ...$parameters);
64
        }
65
66 6
        return null;
67
    }
68
69
    /**
70
     * Calls the object's methods one by one and returns the first non-empty value.
71
     *
72
     * @param  Closure|callable|string  $class
73
     * @param  string|array  $methods
74
     * @param  mixed  ...$parameters
75
     *
76
     * @throws \ReflectionException
77
     *
78
     * @return mixed
79
     */
80 4
    public function runMethods($class, $methods, ...$parameters)
81
    {
82 4
        if ($value = $this->callback($class, $methods, ...$parameters)) {
83 2
            return $value;
84
        }
85
86 4
        foreach (ArrHelper::wrap($methods) as $method) {
87 4
            if ($value = $this->runExists($class, $method, ...$parameters)) {
88 4
                return $value;
89
            }
90
        }
91
92 2
        return null;
93
    }
94
95
    /**
96
     * Calls a method of an object that matches a class.
97
     *
98
     * @param  array  $map
99
     * @param  mixed  $value
100
     * @param  mixed  ...$parameters
101
     *
102
     * @throws \ReflectionException
103
     * @return mixed|null
104
     */
105 6
    public function runOf(array $map, $value, ...$parameters)
106
    {
107 6
        if ($this->validated($value)) {
108 4
            foreach ($map as $class => $method) {
109 4
                if (InstanceHelper::of($value, $class)) {
110 4
                    return $this->runExists($value, $method, ...$parameters);
111
                }
112
            }
113
        }
114
115 6
        return null;
116
    }
117
118
    /**
119
     * Gets the result of executing code in the specified class, if allowed.
120
     *
121
     * @param  bool  $when
122
     * @param  Closure|callable|string  $class
123
     * @param  string  $method
124
     * @param  mixed  ...$parameters
125
     *
126
     * @throws \ReflectionException
127
     *
128
     * @return mixed|null
129
     */
130 4
    public function when(bool $when, $class, string $method, ...$parameters)
131
    {
132 4
        return $when ? $this->run($class, $method, ...$parameters) : null;
133
    }
134
135 16
    protected function callback($class, ...$parameters)
136
    {
137 16
        if (is_callable($class)) {
138 8
            return $class(...$parameters);
139
        }
140
141 16
        return null;
142
    }
143
144 16
    protected function resolve($class)
145
    {
146 16
        return new $class();
147
    }
148
149 16
    protected function reflection($class): ReflectionClass
150
    {
151 16
        return ReflectionHelper::resolve($class);
152
    }
153
154 18
    protected function validate($class): void
155
    {
156 18
        if (! $this->validated($class)) {
157 2
            throw new InvalidArgumentException('Argument #1 must be either a class reference or an instance of a class, ' . gettype($class) . ' given.');
158
        }
159 16
    }
160
161 20
    protected function validated($class): bool
162
    {
163 20
        return is_callable($class) || InstanceHelper::exists($class) || IsHelper::object($class) || InstanceHelper::of($class, Closure::class);
164
    }
165
}
166