Passed
Push — master ( 829500...1175ab )
by Kevin
08:08
created

Proxy::__set()   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
namespace Zenstruck\Foundry;
4
5
use Doctrine\Persistence\ObjectManager;
6
use Doctrine\Persistence\ObjectRepository;
7
use PHPUnit\Framework\Assert;
8
9
/**
10
 * @author Kevin Bond <[email protected]>
11
 */
12
final class Proxy
13
{
14
    private static bool $autoRefreshByDefault = true;
15
    private static ?Instantiator $instantiator = null;
16
17
    private object $object;
18
    private string $class;
19
    private ?bool $autoRefresh = null;
20
21 62
    public function __construct(object $object)
22
    {
23 62
        $this->object = $object;
24 62
        $this->class = \get_class($object);
25 62
    }
26
27 16
    public function __call(string $method, array $arguments)
28
    {
29 16
        return $this->object()->{$method}(...$arguments);
30
    }
31
32 2
    public function __get(string $name)
33
    {
34 2
        return $this->object()->{$name};
35
    }
36
37 2
    public function __set(string $name, $value): void
38
    {
39 2
        $this->object()->{$name} = $value;
40 2
    }
41
42 2
    public function __unset(string $name): void
43
    {
44 2
        unset($this->object()->{$name});
45 2
    }
46
47 2
    public function __isset(string $name): bool
48
    {
49 2
        return isset($this->object()->{$name});
50
    }
51
52 4
    public function __toString(): string
53
    {
54 4
        if (!\method_exists($this->object, '__toString')) {
55 2
            throw new \RuntimeException(\sprintf('Proxied object "%s" cannot be converted to a string.', $this->class));
56
        }
57
58 2
        return $this->object()->__toString();
59
    }
60
61 34
    public function object(): object
62
    {
63 34
        if ($this->autoRefresh ?? self::$autoRefreshByDefault) {
64 16
            $this->refresh();
65
        }
66
67 34
        return $this->object;
68
    }
69
70 2
    public function save(): self
71
    {
72 2
        $this->objectManager()->persist($this->object);
73 2
        $this->objectManager()->flush();
74
75 2
        return $this;
76
    }
77
78 2
    public function remove(): self
79
    {
80 2
        $this->objectManager()->remove($this->object);
81 2
        $this->objectManager()->flush();
82
83 2
        return $this;
84
    }
85
86 18
    public function refresh(): self
87
    {
88 18
        if ($this->objectManager()->contains($this->object)) {
89 16
            $this->objectManager()->refresh($this->object);
90
91 16
            return $this;
92
        }
93
94 4
        if (!$object = $this->fetchObject()) {
95 2
            throw new \RuntimeException('The object no longer exists.');
96
        }
97
98 2
        $this->object = $object;
99
100 2
        return $this;
101
    }
102
103
    /**
104
     * @param mixed $value
105
     */
106 4
    public function forceSet(string $property, $value): self
107
    {
108 4
        return $this->forceSetAll([$property => $value]);
109
    }
110
111 4
    public function forceSetAll(array $properties): self
112
    {
113 4
        $object = $this->object();
114
115 4
        foreach ($properties as $property => $value) {
116 4
            self::instantiator()->forceSet($object, $property, $value);
117
        }
118
119 4
        return $this;
120
    }
121
122
    /**
123
     * @return mixed
124
     */
125 2
    public function forceGet(string $property)
126
    {
127 2
        return self::instantiator()->forceGet($this->object(), $property);
128
    }
129
130
    /**
131
     * @return RepositoryProxy|ObjectRepository
132
     */
133 2
    public function repository(bool $proxy = true): ObjectRepository
134
    {
135 2
        return PersistenceManager::repositoryFor($this->class, $proxy);
136
    }
137
138 38
    public function withAutoRefresh(): self
139
    {
140 38
        $this->autoRefresh = true;
141
142 38
        return $this;
143
    }
144
145 14
    public function withoutAutoRefresh(): self
146
    {
147 14
        $this->autoRefresh = false;
148
149 14
        return $this;
150
    }
151
152 2
    public function assertPersisted(): self
153
    {
154
        // todo improve message
155 2
        Assert::assertNotNull($this->fetchObject(), 'The object is not persisted.');
156
157 2
        return $this;
158
    }
159
160 2
    public function assertNotPersisted(): self
161
    {
162
        // todo improve message
163 2
        Assert::assertNull($this->fetchObject(), 'The object is persisted but it should not be.');
164
165 2
        return $this;
166
    }
167
168 4
    public static function autoRefreshByDefault(bool $value): void
169
    {
170 4
        self::$autoRefreshByDefault = $value;
171 4
    }
172
173
    /**
174
     * Todo - move to RepositoryProxy?
175
     */
176 8
    private function fetchObject(): ?object
177
    {
178 8
        $id = $this->objectManager()->getClassMetadata($this->class)->getIdentifierValues($this->object);
179
180 8
        return empty($id) ? null : $this->objectManager()->find($this->class, $id);
181
    }
182
183 22
    private function objectManager(): ObjectManager
184
    {
185 22
        return PersistenceManager::objectManagerFor($this->class);
186
    }
187
188 4
    private static function instantiator(): Instantiator
189
    {
190 4
        return self::$instantiator ?: self::$instantiator = Instantiator::default()->strict();
191
    }
192
}
193