Passed
Push — main ( 1a8771...d7bb24 )
by Andrey
11:52 queued 10:31
created

Call::runMethods()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4.0466

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 6
c 1
b 0
f 0
nc 4
nop 3
dl 0
loc 13
ccs 6
cts 7
cp 0.8571
crap 4.0466
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  callable|Closure|string  $class
19
     * @param  string  $method
20
     * @param  mixed  ...$parameters
21
     *
22
     * @throws \ReflectionException
23
     *
24
     * @return mixed
25
     */
26 12
    public function run($class, string $method, ...$parameters)
27
    {
28 12
        $this->validate($class);
29
30 10
        if ($value = $this->callback($class, $method, ...$parameters)) {
31 4
            return $value;
32
        }
33
34 10
        $reflect = $this->reflection($class)->getMethod($method);
35
36 10
        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 10
            $class = $this->resolve($class);
38
        }
39
40 10
        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  callable|Closure|string  $class
47
     * @param  string  $method
48
     * @param  mixed  ...$parameters
49
     *
50
     * @throws \ReflectionException
51
     *
52
     * @return mixed
53
     */
54 6
    public function runExists($class, string $method, ...$parameters)
55
    {
56 6
        $this->validate($class);
57
58 6
        if ($value = $this->callback($class, $method, ...$parameters)) {
59 2
            return $value;
60
        }
61
62 6
        if (method_exists($class, $method)) {
63 6
            return $this->run($class, $method, ...$parameters);
64
        }
65
66 2
        return null;
67
    }
68
69
    /**
70
     * Calls the object's methods one by one and returns the first non-empty value.
71
     *
72
     * @param  callable|Closure|string  $class
73
     * @param  array|string  $methods
74
     * @param  mixed  ...$parameters
75
     *
76
     * @throws \ReflectionException
77
     *
78
     * @return mixed
79
     */
80 2
    public function runMethods($class, $methods, ...$parameters)
81
    {
82 2
        if ($value = $this->callback($class, $methods, ...$parameters)) {
83 2
            return $value;
84
        }
85
86 2
        foreach (ArrHelper::wrap($methods) as $method) {
87 2
            if ($value = $this->runExists($class, $method, ...$parameters)) {
88 2
                return $value;
89
            }
90
        }
91
92
        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
     *
104
     * @return mixed|null
105
     */
106 4
    public function runOf(array $map, $value, ...$parameters)
107
    {
108 4
        if ($this->validated($value)) {
109 2
            foreach ($map as $class => $method) {
110 2
                if (InstanceHelper::of($value, $class)) {
111 2
                    return $this->runExists($value, $method, ...$parameters);
112
                }
113
            }
114
        }
115
116 4
        return null;
117
    }
118
119
    /**
120
     * Gets the result of executing code in the specified class, if allowed.
121
     *
122
     * @param  bool  $when
123
     * @param  callable|Closure|string  $class
124
     * @param  string  $method
125
     * @param  mixed  ...$parameters
126
     *
127
     * @throws \ReflectionException
128
     *
129
     * @return mixed|null
130
     */
131 4
    public function when(bool $when, $class, string $method, ...$parameters)
132
    {
133 4
        return $when ? $this->run($class, $method, ...$parameters) : null;
134
    }
135
136 10
    protected function callback($class, ...$parameters)
137
    {
138 10
        if (is_callable($class)) {
139 8
            return $class(...$parameters);
140
        }
141
142 10
        return null;
143
    }
144
145 10
    protected function resolve($class)
146
    {
147 10
        return IsHelper::object($class) ? $class : new $class();
148
    }
149
150 10
    protected function reflection($class): ReflectionClass
151
    {
152 10
        return ReflectionHelper::resolve($class);
153
    }
154
155 12
    protected function validate($class): void
156
    {
157 12
        if (! $this->validated($class)) {
158 2
            throw new InvalidArgumentException('Argument #1 must be either a class reference or an instance of a class, ' . gettype($class) . ' given.');
159
        }
160 10
    }
161
162 14
    protected function validated($class): bool
163
    {
164 14
        return is_callable($class) || InstanceHelper::exists($class) || IsHelper::object($class) || InstanceHelper::of($class, Closure::class);
165
    }
166
}
167