Call::run()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 7
c 1
b 0
f 0
nc 3
nop 3
dl 0
loc 15
ccs 8
cts 8
cp 1
crap 4
rs 10
1
<?php
2
/*
3
 * This file is part of the "andrey-helldar/support" project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author Andrey Helldar <[email protected]>
9
 *
10
 * @copyright 2021 Andrey Helldar
11
 *
12
 * @license MIT
13
 *
14
 * @see https://github.com/andrey-helldar/support
15
 */
16
17
namespace Helldar\Support\Helpers;
18
19
use Closure;
20
use Helldar\Support\Facades\Helpers\Arr as ArrHelper;
21
use Helldar\Support\Facades\Helpers\Instance as InstanceHelper;
22
use Helldar\Support\Facades\Helpers\Is as IsHelper;
23
use Helldar\Support\Facades\Helpers\Reflection as ReflectionHelper;
24
use InvalidArgumentException;
25
use ReflectionClass;
26
27
class Call
28
{
29
    /**
30
     * Gets the result of executing code in the specified class.
31
     *
32
     * @param  callable|Closure|string  $class
33
     * @param  string  $method
34
     * @param  mixed  ...$parameters
35
     *
36
     * @throws \ReflectionException
37
     *
38
     * @return mixed
39
     */
40 14
    public function run($class, string $method, ...$parameters)
41
    {
42 14
        $this->validate($class);
43
44 12
        if ($value = $this->callback($class, $method, ...$parameters)) {
45 4
            return $value;
46
        }
47
48 12
        $reflect = $this->reflection($class)->getMethod($method);
49
50 12
        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

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