GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#190)
by joseph
20:38
created

mapCriteriaSetUuidsToStrings()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 5
nc 5
nop 1
dl 0
loc 8
ccs 0
cts 8
cp 0
crap 20
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\Entity\Repositories;
4
5
use Doctrine\Common\Collections\Criteria;
6
use Doctrine\DBAL\Types\ConversionException;
7
use Doctrine\ORM\EntityManagerInterface;
8
use Doctrine\ORM\EntityRepository;
9
use Doctrine\ORM\LazyCriteriaCollection;
10
use Doctrine\ORM\Mapping\ClassMetadata;
11
use Doctrine\ORM\NativeQuery;
12
use Doctrine\ORM\Query;
13
use Doctrine\ORM\QueryBuilder;
14
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
15
use EdmondsCommerce\DoctrineStaticMeta\Entity\Factory\EntityFactoryInterface;
16
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\EntityInterface;
17
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
18
use EdmondsCommerce\DoctrineStaticMeta\MappingHelper;
19
use Ramsey\Uuid\UuidInterface;
20
21
/**
22
 * Class AbstractEntityRepository
23
 *
24
 * This provides a base class that handles instantiating the correctly configured EntityRepository and provides an
25
 * extensible baseline for further customisation
26
 *
27
 * We have extracted an interface from the standard Doctrine EntityRepository and implemented that
28
 * However, so we can add type safety, we can't "actually" implement it
29
 *
30
 * We have also deliberately left out the magic calls. Please make real methods in your concrete repository class
31
 *
32
 * Note, there are quite a few PHPMD warnings, however it needs to respect the legacy interface so they are being
33
 * suppressed
34
 *
35
 * @package EdmondsCommerce\DoctrineStaticMeta\Entity\Repositories
36
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
37
 * @SuppressWarnings(PHPMD.ExcessivePublicCount)
38
 * @SuppressWarnings(PHPMD.NumberOfChildren)
39
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
40
 */
41
abstract class AbstractEntityRepository implements EntityRepositoryInterface
42
{
43
    /**
44
     * @var EntityManagerInterface
45
     */
46
    protected $entityManager;
47
    /**
48
     * @var EntityRepository
49
     */
50
    protected $entityRepository;
51
    /**
52
     * @var string
53
     */
54
    protected $repositoryFactoryFqn;
55
    /**
56
     * @var ClassMetadata|null
57
     */
58
    protected $metaData;
59
    /**
60
     * @var NamespaceHelper
61
     */
62
    protected $namespaceHelper;
63
    /**
64
     * @var EntityFactoryInterface
65
     */
66
    private $entityFactory;
67
68
    /**
69
     * AbstractEntityRepositoryFactory constructor.
70
     *
71
     * @param EntityManagerInterface $entityManager
72
     * @param EntityFactoryInterface $entityFactory
73
     * @param NamespaceHelper|null   $namespaceHelper
74
     */
75
    public function __construct(
76
        EntityManagerInterface $entityManager,
77
        EntityFactoryInterface $entityFactory,
78
        NamespaceHelper $namespaceHelper
79
    ) {
80
        $this->entityManager   = $entityManager;
81
        $this->namespaceHelper = $namespaceHelper;
82
        $this->entityFactory   = $entityFactory;
83
        $this->initRepository();
84
    }
85
86
    protected function initRepository(): void
87
    {
88
        if (null === $this->metaData) {
89
            $entityFqn      = $this->getEntityFqn();
90
            $this->metaData = $this->entityManager->getClassMetadata($entityFqn);
91
        }
92
93
        $this->entityRepository = new EntityRepository($this->entityManager, $this->metaData);
94
    }
95
96
    protected function getEntityFqn(): string
97
    {
98
        return '\\' . \str_replace(
99
                [
100
                    'Entity\\Repositories',
101
                ],
102
                [
103
                    'Entities',
104
                ],
105
                $this->namespaceHelper->cropSuffix(static::class, 'Repository')
106
            );
107
    }
108
109
    public function getRandomResultFromQueryBuilder(QueryBuilder $queryBuilder, string $entityAlias): ?EntityInterface
110
    {
111
        $count = $this->getCountForQueryBuilder($queryBuilder, $entityAlias);
112
        if (0 === $count) {
113
            return null;
114
        }
115
116
        $queryBuilder->setMaxResults(1);
117
        $limitIndex = random_int(0, $count - 1);
118
        $results    = $queryBuilder->getQuery()
119
                                   ->setFirstResult($limitIndex)
120
                                   ->execute();
121
        $entity     = current($results);
122
        if (null === $entity) {
123
            return null;
124
        }
125
        $this->initialiseEntity($entity);
126
127
        return $entity;
128
    }
129
130
    public function getCountForQueryBuilder(QueryBuilder $queryBuilder, string $aliasToCount): int
131
    {
132
        $clone = clone $queryBuilder;
133
        $clone->select($queryBuilder->expr()->count($aliasToCount));
134
135
        return (int)$clone->getQuery()->getSingleScalarResult();
136
    }
137
138
    public function initialiseEntity(EntityInterface $entity)
139
    {
140
        $this->entityFactory->initialiseEntity($entity);
141
142
        return $entity;
143
    }
144
145
    /**
146
     * @return array|EntityInterface[]
147
     */
148
    public function findAll(): array
149
    {
150
        return $this->initialiseEntities($this->entityRepository->findAll());
151
    }
152
153
    public function initialiseEntities($entities)
154
    {
155
        foreach ($entities as $entity) {
156
            $this->initialiseEntity($entity);
157
        }
158
159
        return $entities;
160
    }
161
162
    /**
163
     * @param mixed    $id
164
     * @param int|null $lockMode
165
     * @param int|null $lockVersion
166
     *
167
     * @return EntityInterface
168
     * @throws DoctrineStaticMetaException
169
     */
170
    public function get($id, ?int $lockMode = null, ?int $lockVersion = null)
171
    {
172
        try {
173
            $entity = $this->find($id, $lockMode, $lockVersion);
174
        } catch (ConversionException $e) {
175
            $error = 'Failed getting by id ' . $id
176
                     . ', unless configured as an int ID entity, this should be a valid UUID';
177
            throw new DoctrineStaticMetaException($error, $e->getCode(), $e);
178
        }
179
        if ($entity === null) {
180
            throw new DoctrineStaticMetaException('Could not find the entity with id ' . $id);
181
        }
182
183
        return $this->initialiseEntity($entity);
184
    }
185
186
    /**
187
     * @param mixed    $id
188
     * @param int|null $lockMode
189
     * @param int|null $lockVersion
190
     *
191
     * @return EntityInterface|null
192
     */
193
    public function find($id, ?int $lockMode = null, ?int $lockVersion = null)
194
    {
195
        $entity = $this->entityRepository->find($id, $lockMode, $lockVersion);
196
        if (null === $entity) {
197
            return null;
198
        }
199
        if ($entity instanceof EntityInterface) {
200
            $this->initialiseEntity($entity);
201
202
            return $entity;
203
        }
204
    }
205
206
    /**
207
     * @param array      $criteria
208
     * @param array|null $orderBy
209
     *
210
     * @return EntityInterface
211
     */
212
    public function getOneBy(array $criteria, ?array $orderBy = null)
213
    {
214
        $result = $this->findOneBy($criteria, $orderBy);
215
        if ($result === null) {
216
            throw new \RuntimeException('Could not find the entity');
217
        }
218
219
        return $this->initialiseEntity($result);
220
    }
221
222
    public function mapCriteriaSetUuidsToStrings(array &$criteria): void
223
    {
224
        foreach ($criteria as $property => &$value) {
225
            if ($value instanceof EntityInterface) {
226
                $value = $value->getId();
227
            }
228
            if ($value instanceof UuidInterface) {
229
                $value = $value->toString();
230
            }
231
        }
232
    }
233
234
    /**
235
     * @param array      $criteria
236
     * @param array|null $orderBy
237
     *
238
     * @return EntityInterface|null
239
     */
240
    public function findOneBy(array $criteria, ?array $orderBy = null)
241
    {
242
        $this->mapCriteriaSetUuidsToStrings($criteria);
243
        $entity = $this->entityRepository->findOneBy($criteria, $orderBy);
244
        if (null === $entity) {
245
            return null;
246
        }
247
        if ($entity instanceof EntityInterface) {
248
            $this->initialiseEntity($entity);
249
250
            return $entity;
251
        }
252
    }
253
254
    /**
255
     * @param array $criteria
256
     *
257
     * @return EntityInterface|null
258
     */
259
    public function getRandomOneBy(array $criteria)
260
    {
261
        $found = $this->getRandomBy($criteria, 1);
262
        if ([] === $found) {
263
            throw new \RuntimeException('Failed finding any Entities with this criteria');
264
        }
265
        $entity = current($found);
266
        if ($entity instanceof EntityInterface) {
267
            return $entity;
268
        }
269
        throw new \RuntimeException('Unexpected Entity Type ' . get_class($entity));
270
    }
271
272
    /**
273
     * @param array $criteria
274
     *
275
     * @param int   $numToGet
276
     *
277
     * @return EntityInterface[]|array
278
     */
279
    public function getRandomBy(array $criteria, int $numToGet = 1): array
280
    {
281
        $count = $this->count($criteria);
282
        if (0 === $count) {
283
            return [];
284
        }
285
        $randOffset = rand(0, $count - $numToGet);
286
287
        return $this->findBy($criteria, null, $numToGet, $randOffset);
288
    }
289
290
    public function count(array $criteria = []): int
291
    {
292
        $this->mapCriteriaSetUuidsToStrings($criteria);
293
        return $this->entityRepository->count($criteria);
294
    }
295
296
    /**
297
     * @return array|EntityInterface[]
298
     */
299
    public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
300
    {
301
        $this->mapCriteriaSetUuidsToStrings($criteria);
302
        return $this->initialiseEntities($this->entityRepository->findBy($criteria, $orderBy, $limit, $offset));
303
    }
304
305
    public function matching(Criteria $criteria): LazyCriteriaCollection
306
    {
307
        $this->mapCriteriaSetUuidsToStrings($criteria);
0 ignored issues
show
Bug introduced by
$criteria of type Doctrine\Common\Collections\Criteria is incompatible with the type array expected by parameter $criteria of EdmondsCommerce\Doctrine...eriaSetUuidsToStrings(). ( Ignorable by Annotation )

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

307
        $this->mapCriteriaSetUuidsToStrings(/** @scrutinizer ignore-type */ $criteria);
Loading history...
308
        $collection = $this->entityRepository->matching($criteria);
309
        if ($collection instanceof LazyCriteriaCollection) {
0 ignored issues
show
introduced by
$collection is always a sub-type of Doctrine\ORM\LazyCriteriaCollection.
Loading history...
310
            return $this->initialiseEntities($collection);
311
        }
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 309 is false. This is incompatible with the type-hinted return Doctrine\ORM\LazyCriteriaCollection. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
312
    }
313
314
    public function createQueryBuilder(string $alias, string $indexBy = null): QueryBuilder
315
    {
316
        #return $this->entityRepository->createQueryBuilder($alias, $indexBy);
317
        return (new UuidQueryBuilder($this->entityManager))
318
            ->select($alias)
319
            ->from($this->getClassName(), $alias, $indexBy);
320
    }
321
322
    public function getClassName(): string
323
    {
324
        return $this->entityRepository->getClassName();
325
    }
326
327
    public function createResultSetMappingBuilder(string $alias): Query\ResultSetMappingBuilder
328
    {
329
        return $this->entityRepository->createResultSetMappingBuilder($alias);
330
    }
331
332
    public function createNamedQuery(string $queryName): Query
333
    {
334
        return $this->entityRepository->createNamedQuery($queryName);
335
    }
336
337
    public function createNativeNamedQuery(string $queryName): NativeQuery
338
    {
339
        return $this->entityRepository->createNativeNamedQuery($queryName);
340
    }
341
342
    public function clear(): void
343
    {
344
        $this->entityRepository->clear();
345
    }
346
}
347