Passed
Push — main ( 17c86c...a6713e )
by Michael
04:02
created

HelpsProxies::sliceParameters()   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 2
dl 0
loc 3
ccs 2
cts 2
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
use MichaelRubel\EnhancedContainer\Exceptions\PropertyNotFoundException;
9
10
trait HelpsProxies
11
{
12
    /**
13
     * @param string      $class
14
     * @param array       $dependencies
15
     * @param string|null $context
16
     *
17
     * @return object
18
     */
19 53
    public function resolvePassedClass(string $class, array $dependencies = [], ?string $context = null): object
20
    {
21 53
        $class        = $this->getClassForResolution($class, $context);
22 53
        $dependencies = $this->getDependencies($class, $dependencies);
23
24 53
        return resolve($class, $dependencies);
25
    }
26
27
    /**
28
     * Get the class for resolution.
29
     *
30
     * @param string      $class
31
     * @param string|null $context
32
     *
33
     * @return string
34
     */
35 53
    public function getClassForResolution(string $class, ?string $context = null): string
36
    {
37 53
        return ! is_null($context) && isset(app()->contextual[$context])
38 1
            ? $this->getContextualConcrete($class, $context)
39 53
            : $class;
40
    }
41
42
    /**
43
     * Try to get the contextual concrete.
44
     *
45
     * @param string      $class
46
     * @param string|null $context
47
     *
48
     * @return string
49
     */
50 1
    public function getContextualConcrete(string $class, ?string $context = null): string
51
    {
52 1
        return app()->contextual[$context][$class] ?? $class;
53
    }
54
55
    /**
56
     * Resolve class dependencies.
57
     *
58
     * @param string $class
59
     * @param array  $dependencies
60
     *
61
     * @return array
62
     * @throws \ReflectionException
63
     */
64 53
    public function getDependencies(string $class, array $dependencies = []): array
65
    {
66 53
        if (! empty($dependencies) && ! Arr::isAssoc($dependencies)) {
67
            /** @var class-string $class */
68 2
            $constructor = (new \ReflectionClass($class))->getConstructor();
69
70 2
            if ($constructor) {
71 2
                $dependencies = $this->makeContainerParameters(
72 2
                    $constructor->getParameters(),
73
                    $dependencies
74
                );
75
            }
76
        }
77
78 53
        return $dependencies;
79
    }
80
81
    /**
82
     * @param object $class
83
     * @param string $method
84
     * @param array  $parameters
85
     *
86
     * @return array
87
     * @throws \ReflectionException
88
     */
89 50
    public function getPassedParameters(object $class, string $method, array $parameters): array
90
    {
91 50
        if (empty($parameters)) {
92 25
            return $parameters;
93
        }
94
95 28
        return $this->makeContainerParameters(
96 28
            (new \ReflectionMethod($class, $method))->getParameters(),
97
            $parameters
98
        );
99
    }
100
101
    /**
102
     * Combine parameters to make it container-readable.
103
     *
104
     * @param array $reflectionParameters
105
     * @param array $methodParameters
106
     *
107
     * @return array
108
     */
109 27
    public function makeContainerParameters(array $reflectionParameters, array $methodParameters): array
110
    {
111 27
        $base = current($methodParameters);
112
113 27
        if ($this->isOrderable($base, $reflectionParameters, $methodParameters)) {
114 1
            return $base;
115
        }
116
117 27
        $reflectionParameters = $this->sliceParameters(
118 27
            $reflectionParameters,
119
            $methodParameters
120
        );
121
122 27
        $methodParameters = $this->sliceParameters(
123 27
            $methodParameters,
124
            $reflectionParameters
125
        );
126
127 27
        return collect($reflectionParameters)
128 27
            ->map
129 27
            ->getName()
130 27
            ->combine($methodParameters)
131 27
            ->all();
132
    }
133
134
    /**
135
     * Determine if the container can handle parameter order.
136
     *
137
     * @param array $base
138
     * @param array $reflectionParameters
139
     * @param array $methodParameters
140
     *
141
     * @return bool
142
     */
143 27
    public function isOrderable(mixed $base, array $reflectionParameters, array $methodParameters): bool
144
    {
145 27
        return is_array($base) && Arr::isAssoc($base) && single($methodParameters) <=> single($reflectionParameters);
146
    }
147
148
    /**
149
     * Slice an array to align the parameters.
150
     *
151
     * @param array $parameters
152
     * @param array $countable
153
     *
154
     * @return array
155
     */
156 27
    public function sliceParameters(array $parameters, array $countable): array
157
    {
158 27
        return array_slice($parameters, 0, count($countable));
159
    }
160
161
    /**
162
     * Convert the object to its namespace.
163
     *
164
     * @param object|string $object
165
     *
166
     * @return string
167
     */
168 49
    public function convertToNamespace(object|string $object): string
169
    {
170 49
        return is_string($object)
171 42
            ? $object
172 49
            : $object::class;
173
    }
174
175
    /**
176
     * Handle property error.
177
     *
178
     * @param string $name
179
     * @param object $instance
180
     *
181
     * @throws PropertyNotFoundException
182
     */
183 3
    public function throwPropertyNotFoundException(string $name, object $instance): self
184
    {
185 3
        throw new PropertyNotFoundException(sprintf(
186 3
            'Call to undefined property %s::%s()',
187
            $name,
188 3
            $instance::class
189
        ));
190
    }
191
}
192