Passed
Pull Request — main (#4)
by Michael
03:29
created

CallProxy::__set()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 6
b 0
f 0
nc 2
nop 2
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MichaelRubel\EnhancedContainer\Core;
6
7
use Illuminate\Support\Traits\ForwardsCalls;
8
use MichaelRubel\EnhancedContainer\Call;
9
use MichaelRubel\EnhancedContainer\Exceptions\InstanceInteractionException;
10
use MichaelRubel\EnhancedContainer\Traits\InteractsWithContainer;
11
12
class CallProxy implements Call
13
{
14
    use InteractsWithContainer, ForwardsCalls;
0 ignored issues
show
introduced by
The trait MichaelRubel\EnhancedCon...\InteractsWithContainer requires some properties which are not provided by MichaelRubel\EnhancedContainer\Core\CallProxy: $contextual, $map
Loading history...
15
16
    /**
17
     * @var object
18
     */
19
    protected object $instance;
20
21
    /**
22
     * @var object
23
     */
24
    protected object $previous;
25
26
    /**
27
     * @var array
28
     */
29
    protected array $state = [];
30
31
    /**
32
     * CallProxy constructor.
33
     *
34
     * @param  object|string  $class
35
     * @param  array  $dependencies
36
     * @param  string|null  $context
37
     */
38 59
    public function __construct(
39
        object | string $class,
40
        array $dependencies = [],
41
        ?string $context = null
42
    ) {
43 59
        $this->instance = $this->resolvePassedClass($class, $dependencies, $context);
44
    }
45
46
    /**
47
     * Gets the internal property by name.
48
     *
49
     * @param  string  $property
50
     *
51
     * @return mixed
52
     */
53 10
    public function getInternal(string $property): mixed
54
    {
55 10
        return $this->{$property};
56
    }
57
58
    /**
59
     * Perform the container call.
60
     *
61
     * @param  object  $service
62
     * @param  string  $method
63
     * @param  array  $parameters
64
     *
65
     * @return mixed
66
     */
67 51
    protected function containerCall(object $service, string $method, array $parameters): mixed
68
    {
69
        try {
70 51
            return app()->call(
71 51
                [$service, $method],
72 51
                $this->getPassedParameters($service, $method, $parameters)
73
            );
74 9
        } catch (\ReflectionException) {
75 3
            return $this->forwardCallTo($service, $method, $parameters);
76
        }
77
    }
78
79
    /**
80
     * @return void
81
     */
82 14
    protected function findForwardedInstance(): void
83
    {
84 14
        $clue = $this->instance::class . Forwarding::CONTAINER_KEY;
85
86 14
        $newInstance = rescue(fn () => app($clue), report: false);
87
88 14
        if (! is_null($newInstance)) {
89 11
            $this->previous = $this->instance;
90 11
            $this->instance = $newInstance;
91
        }
92
    }
93
94
    /**
95
     * @param  string  $name
96
     * @param  string  $type
97
     *
98
     * @return void
99
     */
100 56
    protected function setState(string $name, string $type): void
101
    {
102 56
        $this->state[$name] = $type;
103
    }
104
105
    /**
106
     * @param  string  $name
107
     *
108
     * @return bool
109
     */
110 12
    protected function stateChanged(string $name): bool
111
    {
112 12
        return isset($this->state[$name]) && isset($this->previous);
113
    }
114
115
    /**
116
     * Pass the call through container.
117
     *
118
     * @param  string  $method
119
     * @param  array  $parameters
120
     *
121
     * @return mixed
122
     * @throws InstanceInteractionException
123
     */
124 51
    public function __call(string $method, array $parameters): mixed
125
    {
126 51
        if (! method_exists($this->instance, $method)) {
127 10
            if ($this->stateChanged($method)) {
128 1
                throw new InstanceInteractionException;
129
            }
130
131 10
            $this->findForwardedInstance();
132
        }
133
134 51
        $this->setState($method, Call::METHOD);
135
136 51
        return $this->containerCall($this->instance, $method, $parameters);
137
    }
138
139
    /**
140
     * Get the instance's property.
141
     *
142
     * @param  string  $name
143
     *
144
     * @return mixed
145
     * @throws InstanceInteractionException
146
     */
147 7
    public function __get(string $name): mixed
148
    {
149 7
        if (! property_exists($this->instance, $name)) {
150 2
            if ($this->stateChanged($name)) {
151 1
                throw new InstanceInteractionException;
152
            }
153
154 1
            $this->findForwardedInstance();
155
        }
156
157 7
        return rescue(fn () => $this->instance->{$name});
158
    }
159
160
    /**
161
     * Set the instance's property.
162
     *
163
     * @param  string  $name
164
     * @param  mixed  $value
165
     */
166 5
    public function __set(string $name, mixed $value): void
167
    {
168 5
        if (! property_exists($this->instance, $name)) {
169 3
            $this->findForwardedInstance();
170
        }
171
172 5
        $this->setState($name, Call::SET);
173
174 5
        $this->instance->{$name} = $value;
175
    }
176
}
177