Passed
Push — main ( 27d456...a1f0d8 )
by Michael
09:23 queued 06:21
created

HelpsProxies::getBindingConcrete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MichaelRubel\EnhancedContainer\Traits;
6
7
use Illuminate\Support\Arr;
8
9
trait HelpsProxies
10
{
11
    /**
12
     * @param string      $class
13
     * @param array       $dependencies
14
     * @param string|null $context
15
     *
16
     * @return object
17
     */
18 57
    public function resolvePassedClass(string $class, array $dependencies = [], ?string $context = null): object
19
    {
20 57
        $class        = $this->getClassForResolution($class, $context);
21 57
        $dependencies = $this->getDependencies($class, $dependencies);
22
23 57
        return resolve($class, $dependencies);
24
    }
25
26
    /**
27
     * Get the class for resolution.
28
     *
29
     * @param string      $class
30
     * @param string|null $context
31
     *
32
     * @return string
33
     */
34 57
    public function getClassForResolution(string $class, ?string $context = null): string
35
    {
36 57
        return ! is_null($context) && isset(app()->contextual[$context])
37 1
            ? $this->getContextualConcrete($class, $context)
38 57
            : $class;
39
    }
40
41
    /**
42
     * Try to get the contextual concrete.
43
     *
44
     * @param string      $class
45
     * @param string|null $context
46
     *
47
     * @return string
48
     */
49 1
    public function getContextualConcrete(string $class, ?string $context = null): string
50
    {
51 1
        return app()->contextual[$context][$class] ?? $class;
52
    }
53
54
    /**
55
     * @param string $class
56
     *
57
     * @return string
58
     * @throws \ReflectionException
59
     */
60 1
    public function getBindingConcrete(string $class): string
61
    {
62
        return (
63 1
           new \ReflectionFunction(
64 1
               app()->getBindings()[$class]['concrete']
65
           )
66 1
       )->getStaticVariables()['concrete'];
67
    }
68
69
    /**
70
     * Resolve class dependencies.
71
     *
72
     * @param string $class
73
     * @param array  $dependencies
74
     *
75
     * @return array
76
     * @throws \ReflectionException
77
     */
78 57
    public function getDependencies(string $class, array $dependencies = []): array
79
    {
80 57
        if (! empty($dependencies) && ! Arr::isAssoc($dependencies)) {
81 3
            if (! class_exists($class)) {
82 1
                $class = $this->getBindingConcrete($class);
83
            }
84
85
            /** @var class-string $class */
86 3
            $constructor = (new \ReflectionClass($class))->getConstructor();
87
88 3
            if ($constructor) {
89 2
                $dependencies = $this->makeContainerParameters(
90 2
                    $constructor->getParameters(),
91
                    $dependencies
92
                );
93
            }
94
        }
95
96 57
        return $dependencies;
97
    }
98
99
    /**
100
     * @param object $class
101
     * @param string $method
102
     * @param array  $parameters
103
     *
104
     * @return array
105
     * @throws \ReflectionException
106
     */
107 57
    public function getPassedParameters(object $class, string $method, array $parameters): array
108
    {
109 57
        if (empty($parameters) || Arr::isAssoc($parameters)) {
110 32
            return $parameters;
111
        }
112
113 28
        return $this->makeContainerParameters(
114 28
            (new \ReflectionMethod($class, $method))->getParameters(),
115
            $parameters
116
        );
117
    }
118
119
    /**
120
     * Combine parameters to make it container-readable.
121
     *
122
     * @param array $reflectionParameters
123
     * @param array $methodParameters
124
     *
125
     * @return array
126
     */
127 27
    public function makeContainerParameters(array $reflectionParameters, array $methodParameters): array
128
    {
129 27
        $base = current($methodParameters);
130
131 27
        if ($this->isOrderable($base, $reflectionParameters, $methodParameters)) {
132 1
            return $base;
133
        }
134
135 27
        return collect($this->sliceParameters($reflectionParameters, $methodParameters))
0 ignored issues
show
Bug introduced by
$this->sliceParameters($...ers, $methodParameters) of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

135
        return collect(/** @scrutinizer ignore-type */ $this->sliceParameters($reflectionParameters, $methodParameters))
Loading history...
136 27
            ->map->getName()
137 27
            ->combine($this->sliceParameters($methodParameters, $reflectionParameters))
138 27
            ->all();
139
    }
140
141
    /**
142
     * Check if the container can handle the order of passed parameters.
143
     *
144
     * @param array $base
145
     * @param array $reflectionParameters
146
     * @param array $methodParameters
147
     *
148
     * @return bool
149
     */
150 27
    public function isOrderable(mixed $base, array $reflectionParameters, array $methodParameters): bool
151
    {
152 27
        return is_array($base)
153 27
            && Arr::isAssoc($base)
154 27
            && single($methodParameters) <=> single($reflectionParameters);
155
    }
156
157
    /**
158
     * Slice an array to align the parameters.
159
     *
160
     * @param array $parameters
161
     * @param array $countable
162
     *
163
     * @return array
164
     */
165 27
    public function sliceParameters(array $parameters, array $countable): array
166
    {
167 27
        return array_slice($parameters, 0, count($countable));
168
    }
169
170
    /**
171
     * Convert the object to its namespace.
172
     *
173
     * @param object|string $object
174
     *
175
     * @return string
176
     */
177 54
    public function convertToNamespace(object|string $object): string
178
    {
179 54
        return is_string($object)
180 47
            ? $object
181 54
            : $object::class;
182
    }
183
}
184