Passed
Push — main ( 5db1e8...1b324f )
by Michael
04:49 queued 01:17
created

InteractsWithContainer::wrapToClosure()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 3
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 InteractsWithContainer
10
{
11
    /**
12
     * @param  string|object  $class
13
     * @param  array  $dependencies
14
     * @param  string|null  $context
15
     *
16
     * @return object
17
     */
18 60
    protected function getInstance(string|object $class, array $dependencies = [], ?string $context = null): object
19
    {
20 60
        if (is_object($class)) {
21 13
            return $class;
22
        }
23
24 47
        $class        = $this->getClassForResolution($class, $context);
25 47
        $dependencies = $this->getDependencies($class, $dependencies);
26
27 47
        return app($class, $dependencies);
28
    }
29
30
    /**
31
     * Get the class for resolution.
32
     *
33
     * @param  string  $class
34
     * @param  string|null  $context
35
     *
36
     * @return string
37
     */
38 47
    protected function getClassForResolution(string $class, ?string $context = null): string
39
    {
40 47
        return isset(app()->contextual[$context])
41 1
            ? $this->getContextualConcrete($class, $context)
42 47
            : $class;
43
    }
44
45
    /**
46
     * Try to get the contextual concrete.
47
     *
48
     * @param  string  $class
49
     * @param  string|null  $context
50
     *
51
     * @return string
52
     */
53 1
    protected function getContextualConcrete(string $class, ?string $context = null): string
54
    {
55 1
        return app()->contextual[$context][$class] ?? $class;
56
    }
57
58
    /**
59
     * Try to get binding concrete.
60
     *
61
     * @param  string  $class
62
     *
63
     * @return string
64
     * @throws \ReflectionException
65
     */
66 3
    protected function getBindingConcrete(string $class): string
67
    {
68
        return (
69 3
           new \ReflectionFunction(
70 3
               app()->getBindings()[$class]['concrete']
71
           )
72 3
        )->getStaticVariables()['concrete'];
73
    }
74
75
    /**
76
     * Resolve class dependencies.
77
     *
78
     * @param  string  $class
79
     * @param  array  $dependencies
80
     *
81
     * @return array
82
     * @throws \ReflectionException
83
     */
84 47
    protected function getDependencies(string $class, array $dependencies = []): array
85
    {
86 47
        if (! Arr::isAssoc($dependencies)) {
87 44
            if (! class_exists($class)) {
88 3
                $class = $this->getBindingConcrete($class);
89
            }
90
91
            /** @var class-string $class */
92 44
            $constructor = (new \ReflectionClass($class))->getConstructor();
93
94 44
            if ($constructor) {
95 26
                $dependencies = $this->makeContainerParameters(
96 26
                    $constructor->getParameters(),
97
                    $dependencies
98
                );
99
            }
100
        }
101
102 47
        return $dependencies;
103
    }
104
105
    /**
106
     * @param  object  $class
107
     * @param  string  $method
108
     * @param  array  $parameters
109
     *
110
     * @return array
111
     * @throws \ReflectionException
112
     */
113 46
    protected function getParameters(object $class, string $method, array $parameters): array
114
    {
115 46
        if (empty($parameters) || Arr::isAssoc($parameters)) {
116 21
            return $parameters;
117
        }
118
119 27
        return $this->makeContainerParameters(
120 27
            (new \ReflectionMethod($class, $method))->getParameters(),
121
            $parameters
122
        );
123
    }
124
125
    /**
126
     * Combine parameters to make it container-readable.
127
     *
128
     * @param  array  $reflectionParameters
129
     * @param  array  $methodParameters
130
     *
131
     * @return array
132
     */
133 50
    protected function makeContainerParameters(array $reflectionParameters, array $methodParameters): array
134
    {
135 50
        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 50
            ->map->getName()
137 50
            ->combine($this->sliceParameters($methodParameters, $reflectionParameters))
138 50
            ->all();
139
    }
140
141
    /**
142
     * Slice an array to align the parameters.
143
     *
144
     * @param  array  $parameters
145
     * @param  array  $countable
146
     *
147
     * @return array
148
     */
149 50
    protected function sliceParameters(array $parameters, array $countable): array
150
    {
151 50
        return array_slice($parameters, 0, count($countable));
152
    }
153
154
    /**
155
     * Convert the object to its namespace.
156
     *
157
     * @param  object|string  $object
158
     *
159
     * @return string
160
     */
161 15
    protected function convertToNamespace(object|string $object): string
162
    {
163 15
        return is_string($object) ? $object : $object::class;
164
    }
165
}
166