Cancelled
Pull Request — master (#1)
by Kevin
09:12 queued 01:58
created

RepositoryProxy   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 248
Duplicated Lines 0 %

Test Coverage

Coverage 97.53%

Importance

Changes 3
Bugs 1 Features 1
Metric Value
eloc 58
c 3
b 1
f 1
dl 0
loc 248
rs 9.6
ccs 79
cts 81
cp 0.9753
wmc 35

23 Methods

Rating   Name   Duplication   Size   Complexity  
A truncate() 0 9 2
A assertCountGreaterThanOrEqual() 0 6 1
A first() 0 3 1
A assertExists() 0 6 1
A __call() 0 3 1
A __construct() 0 3 1
A assertNotExists() 0 6 1
A assertCountLessThan() 0 6 1
A assertEmpty() 0 3 1
A assertCount() 0 6 1
A assertCountGreaterThan() 0 6 1
A getCount() 0 7 2
A assertCountLessThanOrEqual() 0 6 1
A normalizeCriteria() 0 7 2
A random() 0 3 1
A proxyResult() 0 11 4
A find() 0 11 3
A findOneBy() 0 3 1
A findAll() 0 3 1
A getClassName() 0 3 1
A randomRange() 0 19 4
A findBy() 0 3 1
A randomSet() 0 7 2
1
<?php
2
3
namespace Zenstruck\Foundry;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Doctrine\ORM\EntityRepository;
7
use Doctrine\Persistence\ObjectRepository;
8
use PHPUnit\Framework\Assert;
9
10
/**
11
 * @mixin EntityRepository
12
 *
13
 * @author Kevin Bond <[email protected]>
14
 */
15
final class RepositoryProxy implements ObjectRepository
16
{
17
    private ObjectRepository $repository;
18
19 92
    public function __construct(ObjectRepository $repository)
20
    {
21 92
        $this->repository = $repository;
22 92
    }
23
24 4
    public function __call(string $method, array $arguments)
25
    {
26 4
        return $this->proxyResult($this->repository->{$method}(...$arguments));
27
    }
28
29 20
    public function getCount(): int
30
    {
31 20
        if ($this->repository instanceof EntityRepository) {
32 20
            return $this->repository->count([]);
0 ignored issues
show
Bug introduced by
The method count() does not exist on Doctrine\Persistence\ObjectRepository. It seems like you code against a sub-type of said class. However, the method does not exist in Doctrine\Common\Persistence\ObjectRepository. Are you sure you never get one of those? ( Ignorable by Annotation )

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

32
            return $this->repository->/** @scrutinizer ignore-call */ count([]);
Loading history...
33
        }
34
35
        return \count($this->findAll());
36
    }
37
38 8
    public function assertEmpty(): self
39
    {
40 8
        return $this->assertCount(0);
41
    }
42
43 20
    public function assertCount(int $expectedCount): self
44
    {
45
        // todo add message
46 20
        Assert::assertSame($expectedCount, $this->getCount());
47
48 20
        return $this;
49
    }
50
51 4
    public function assertCountGreaterThan(int $expected): self
52
    {
53
        // todo add message
54 4
        Assert::assertGreaterThan($expected, $this->getCount());
55
56 4
        return $this;
57
    }
58
59 4
    public function assertCountGreaterThanOrEqual(int $expected): self
60
    {
61
        // todo add message
62 4
        Assert::assertGreaterThanOrEqual($expected, $this->getCount());
63
64 4
        return $this;
65
    }
66
67 4
    public function assertCountLessThan(int $expected): self
68
    {
69
        // todo add message
70 4
        Assert::assertLessThan($expected, $this->getCount());
71
72 4
        return $this;
73
    }
74
75 4
    public function assertCountLessThanOrEqual(int $expected): self
76
    {
77
        // todo add message
78 4
        Assert::assertLessThanOrEqual($expected, $this->getCount());
79
80 4
        return $this;
81
    }
82
83
    /**
84
     * @param object|array|mixed $criteria
85
     */
86 8
    public function assertExists($criteria): self
87
    {
88
        // todo add message
89 8
        Assert::assertNotNull($this->find($criteria));
90
91 8
        return $this;
92
    }
93
94
    /**
95
     * @param object|array|mixed $criteria
96
     */
97 4
    public function assertNotExists($criteria): self
98
    {
99
        // todo add message
100 4
        Assert::assertNull($this->find($criteria));
101
102 4
        return $this;
103
    }
104
105
    /**
106
     * @return Proxy|object|null
107
     */
108 4
    public function first(): ?Proxy
109
    {
110 4
        return $this->findOneBy([]);
111
    }
112
113
    /**
114
     * Remove all rows.
115
     */
116 4
    public function truncate(): void
117
    {
118 4
        $om = Factory::configuration()->objectManagerFor($this->getClassName());
119
120 4
        if (!$om instanceof EntityManagerInterface) {
121
            throw new \RuntimeException('This operation is only available when using doctrine/orm');
122
        }
123
124 4
        $om->createQuery("DELETE {$this->getClassName()} e")->execute();
125 4
    }
126
127
    /**
128
     * Fetch one random object.
129
     *
130
     * @return Proxy|object
131
     *
132
     * @throws \RuntimeException if no objects are persisted
133
     */
134 12
    public function random(): Proxy
135
    {
136 12
        return $this->randomSet(1)[0];
137
    }
138
139
    /**
140
     * Fetch a random set of objects.
141
     *
142
     * @param int $number The number of objects to return
143
     *
144
     * @return Proxy[]|object[]
145
     *
146
     * @throws \RuntimeException         if not enough persisted objects to satisfy the number requested
147
     * @throws \InvalidArgumentException if number is less than zero
148
     */
149 28
    public function randomSet(int $number): array
150
    {
151 28
        if ($number < 0) {
152 4
            throw new \InvalidArgumentException(\sprintf('$number must be positive (%d given).', $number));
153
        }
154
155 24
        return $this->randomRange($number, $number);
156
    }
157
158
    /**
159
     * Fetch a random range of objects.
160
     *
161
     * @param int $min The minimum number of objects to return
162
     * @param int $max The maximum number of objects to return
163
     *
164
     * @return Proxy[]|object[]
165
     *
166
     * @throws \RuntimeException         if not enough persisted objects to satisfy the max
167
     * @throws \InvalidArgumentException if min is less than zero
168
     * @throws \InvalidArgumentException if max is less than min
169
     */
170 44
    public function randomRange(int $min, int $max): array
171
    {
172 44
        if ($min < 0) {
173 4
            throw new \InvalidArgumentException(\sprintf('$min must be positive (%d given).', $min));
174
        }
175
176 40
        if ($max < $min) {
177 4
            throw new \InvalidArgumentException(\sprintf('$max (%d) cannot be less than $min (%d).', $max, $min));
178
        }
179
180 36
        $all = \array_values($this->findAll());
181
182 36
        \shuffle($all);
183
184 36
        if (\count($all) < $max) {
185 12
            throw new \RuntimeException(\sprintf('At least %d "%s" object(s) must have been persisted (%d persisted).', $max, $this->getClassName(), \count($all)));
186
        }
187
188 24
        return \array_slice($all, 0, \random_int($min, $max));
189
    }
190
191
    /**
192
     * @param object|array|mixed $criteria
193
     *
194
     * @return Proxy|object|null
195
     */
196 16
    public function find($criteria): ?Proxy
197
    {
198 16
        if ($criteria instanceof Proxy) {
199 4
            $criteria = $criteria->object();
200
        }
201
202 16
        if (!\is_array($criteria)) {
203 4
            return $this->proxyResult($this->repository->find($criteria));
204
        }
205
206 16
        return $this->findOneBy($criteria);
207
    }
208
209
    /**
210
     * @return Proxy[]|object[]
211
     */
212 40
    public function findAll(): array
213
    {
214 40
        return $this->proxyResult($this->repository->findAll());
215
    }
216
217
    /**
218
     * @return Proxy[]|object[]
219
     */
220 4
    public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array
221
    {
222 4
        return $this->proxyResult($this->repository->findBy(self::normalizeCriteria($criteria), $orderBy, $limit, $offset));
223
    }
224
225
    /**
226
     * @return Proxy|object|null
227
     */
228 20
    public function findOneBy(array $criteria): ?Proxy
229
    {
230 20
        return $this->proxyResult($this->repository->findOneBy(self::normalizeCriteria($criteria)));
231
    }
232
233 60
    public function getClassName(): string
234
    {
235 60
        return $this->repository->getClassName();
236
    }
237
238
    /**
239
     * @param mixed $result
240
     *
241
     * @return Proxy|Proxy[]|object|object[]|mixed
242
     */
243 60
    private function proxyResult($result)
244
    {
245 60
        if (\is_object($result) && $this->getClassName() === \get_class($result)) {
246 52
            return Proxy::persisted($result);
247
        }
248
249 52
        if (\is_array($result)) {
250 40
            return \array_map([$this, 'proxyResult'], $result);
251
        }
252
253 12
        return $result;
254
    }
255
256 20
    private static function normalizeCriteria(array $criteria): array
257
    {
258 20
        return \array_map(
259
            function($value) {
260 16
                return $value instanceof Proxy ? $value->object() : $value;
261 20
            },
262 20
            $criteria
263
        );
264
    }
265
}
266