Passed
Pull Request — master (#64)
by Mathieu
17:02
created

RepositoryProxy::assertEmpty()   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
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 1
b 0
f 0
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
    /** @var ObjectRepository */
18
    private $repository;
19
20 256
    public function __construct(ObjectRepository $repository)
21
    {
22 256
        $this->repository = $repository;
23 256
    }
24
25 8
    public function __call(string $method, array $arguments)
26
    {
27 8
        return $this->proxyResult($this->repository->{$method}(...$arguments));
28
    }
29
30 96
    public function getCount(): int
31
    {
32 96
        if ($this->repository instanceof EntityRepository) {
33 96
            return $this->repository->count([]);
34
        }
35
36
        return \count($this->findAll());
37
    }
38
39 32
    public function assertEmpty(string $message = ''): self
40
    {
41 32
        return $this->assertCount(0, $message);
42
    }
43
44 96
    public function assertCount(int $expectedCount, string $message = ''): self
45
    {
46 96
        Assert::assertSame($expectedCount, $this->getCount(), $message);
47
48 96
        return $this;
49
    }
50
51 8
    public function assertCountGreaterThan(int $expected, string $message = ''): self
52
    {
53 8
        Assert::assertGreaterThan($expected, $this->getCount(), $message);
54
55 8
        return $this;
56
    }
57
58 8
    public function assertCountGreaterThanOrEqual(int $expected, string $message = ''): self
59
    {
60 8
        Assert::assertGreaterThanOrEqual($expected, $this->getCount(), $message);
61
62 8
        return $this;
63
    }
64
65 8
    public function assertCountLessThan(int $expected, string $message = ''): self
66
    {
67 8
        Assert::assertLessThan($expected, $this->getCount(), $message);
68
69 8
        return $this;
70
    }
71
72 8
    public function assertCountLessThanOrEqual(int $expected, string $message = ''): self
73
    {
74 8
        Assert::assertLessThanOrEqual($expected, $this->getCount(), $message);
75
76 8
        return $this;
77
    }
78
79
    /**
80
     * @param object|array|mixed $criteria
81
     */
82 16
    public function assertExists($criteria, string $message = ''): self
83
    {
84 16
        Assert::assertNotNull($this->find($criteria), $message);
85
86 16
        return $this;
87
    }
88
89
    /**
90
     * @param object|array|mixed $criteria
91
     */
92 8
    public function assertNotExists($criteria, string $message = ''): self
93
    {
94 8
        Assert::assertNull($this->find($criteria), $message);
95
96 8
        return $this;
97
    }
98
99
    /**
100
     * @return Proxy|object|null
101
     */
102 8
    public function first(string $sortedField = 'id'): ?Proxy
103
    {
104 8
        return $this->findOneBy([], [$sortedField => 'ASC']);
105
    }
106
107
    /**
108
     * @return Proxy|object|null
109
     */
110 8
    public function last(string $sortedField = 'id'): ?Proxy
111
    {
112 8
        return $this->findOneBy([], [$sortedField => 'DESC']);
113
    }
114 8
115
    /**
116
     * Remove all rows.
117
     */
118 8
    public function truncate(): void
119 8
    {
120
        $om = Factory::configuration()->objectManagerFor($this->getClassName());
121
122
        if (!$om instanceof EntityManagerInterface) {
123
            throw new \RuntimeException('This operation is only available when using doctrine/orm');
124
        }
125
126
        $om->createQuery("DELETE {$this->getClassName()} e")->execute();
127
    }
128 32
129
    /**
130 32
     * Fetch one random object.
131
     *
132
     * @return Proxy|object
133
     *
134
     * @throws \RuntimeException if no objects are persisted
135
     */
136
    public function random(): Proxy
137
    {
138
        return $this->randomSet(1)[0];
139
    }
140
141
    /**
142
     * Fetch a random set of objects.
143 64
     *
144
     * @param int $number The number of objects to return
145 64
     *
146 8
     * @return Proxy[]|object[]
147
     *
148
     * @throws \RuntimeException         if not enough persisted objects to satisfy the number requested
149 56
     * @throws \InvalidArgumentException if number is less than zero
150
     */
151
    public function randomSet(int $number): array
152
    {
153
        if ($number < 0) {
154
            throw new \InvalidArgumentException(\sprintf('$number must be positive (%d given).', $number));
155
        }
156
157
        return $this->randomRange($number, $number);
158
    }
159
160
    /**
161
     * Fetch a random range of objects.
162
     *
163
     * @param int $min The minimum number of objects to return
164 96
     * @param int $max The maximum number of objects to return
165
     *
166 96
     * @return Proxy[]|object[]
167 8
     *
168
     * @throws \RuntimeException         if not enough persisted objects to satisfy the max
169
     * @throws \InvalidArgumentException if min is less than zero
170 88
     * @throws \InvalidArgumentException if max is less than min
171 8
     */
172
    public function randomRange(int $min, int $max): array
173
    {
174 80
        if ($min < 0) {
175
            throw new \InvalidArgumentException(\sprintf('$min must be positive (%d given).', $min));
176 80
        }
177
178 80
        if ($max < $min) {
179 24
            throw new \InvalidArgumentException(\sprintf('$max (%d) cannot be less than $min (%d).', $max, $min));
180
        }
181
182 56
        $all = \array_values($this->findAll());
183
184
        \shuffle($all);
185
186
        if (\count($all) < $max) {
187
            throw new \RuntimeException(\sprintf('At least %d "%s" object(s) must have been persisted (%d persisted).', $max, $this->getClassName(), \count($all)));
188
        }
189
190 32
        return \array_slice($all, 0, \random_int($min, $max));
191
    }
192 32
193 8
    /**
194
     * @param object|array|mixed $criteria
195
     *
196 32
     * @return Proxy|object|null
197 8
     */
198
    public function find($criteria): ?Proxy
199
    {
200 32
        if ($criteria instanceof Proxy) {
201
            $criteria = $criteria->object();
202
        }
203
204
        if (!\is_array($criteria)) {
205
            return $this->proxyResult($this->repository->find($criteria));
206 88
        }
207
208 88
        return $this->findOneBy($criteria);
209
    }
210
211
    /**
212
     * @return Proxy[]|object[]
213
     */
214 8
    public function findAll(): array
215
    {
216 8
        return $this->proxyResult($this->repository->findAll());
217
    }
218
219
    /**
220
     * @return Proxy[]|object[]
221
     */
222
    public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array
223
    {
224 48
        return $this->proxyResult($this->repository->findBy(self::normalizeCriteria($criteria), $orderBy, $limit, $offset));
225
    }
226 48
227
    /**
228
     * @param array|null $orderBy Doctrine\ORM\EntityRepository adds this optional parameter
229 136
     *
230
     * @return Proxy|object|null
231 136
     */
232
    public function findOneBy(array $criteria, ?array $orderBy = null): ?Proxy
233
    {
234
        return $this->proxyResult($this->repository->findOneBy(self::normalizeCriteria($criteria), $orderBy));
0 ignored issues
show
Unused Code introduced by
The call to Doctrine\Persistence\ObjectRepository::findOneBy() has too many arguments starting with $orderBy. ( Ignorable by Annotation )

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

234
        return $this->proxyResult($this->repository->/** @scrutinizer ignore-call */ findOneBy(self::normalizeCriteria($criteria), $orderBy));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
235
    }
236
237
    public function getClassName(): string
238
    {
239 136
        return $this->repository->getClassName();
240
    }
241 136
242 120
    /**
243
     * @param mixed $result
244
     *
245 112
     * @return Proxy|Proxy[]|object|object[]|mixed
246 88
     */
247
    private function proxyResult($result)
248
    {
249 24
        if (\is_object($result) && \is_a($result, $this->getClassName())) {
250
            return Proxy::createFromPersisted($result);
251
        }
252 48
253
        if (\is_array($result)) {
254 48
            return \array_map([$this, 'proxyResult'], $result);
255
        }
256 32
257 48
        return $result;
258 48
    }
259
260
    private static function normalizeCriteria(array $criteria): array
261
    {
262
        return \array_map(
263
            function($value) {
264
                return $value instanceof Proxy ? $value->object() : $value;
265
            },
266
            $criteria
267
        );
268
    }
269
}
270