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
Push — master ( 37eca9...fbc101 )
by joseph
236:04 queued 233:05
created

AbstractEntityRepository::getEntityFqn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1.125

Importance

Changes 3
Bugs 0 Features 1
Metric Value
cc 1
eloc 4
c 3
b 0
f 1
nc 1
nop 0
dl 0
loc 10
ccs 5
cts 10
cp 0.5
crap 1.125
rs 10
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 Ramsey\Uuid\UuidInterface;
19
20
/**
21
 * Class AbstractEntityRepository
22
 *
23
 * This provides a base class that handles instantiating the correctly configured EntityRepository and provides an
24
 * extensible baseline for further customisation
25
 *
26
 * We have extracted an interface from the standard Doctrine EntityRepository and implemented that
27
 * However, so we can add type safety, we can't "actually" implement it
28
 *
29
 * We have also deliberately left out the magic calls. Please make real methods in your concrete repository class
30
 *
31
 * Note, there are quite a few PHPMD warnings, however it needs to respect the legacy interface so they are being
32
 * suppressed
33
 *
34
 * @package EdmondsCommerce\DoctrineStaticMeta\Entity\Repositories
35
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
36
 * @SuppressWarnings(PHPMD.ExcessivePublicCount)
37
 * @SuppressWarnings(PHPMD.NumberOfChildren)
38
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
39
 */
40
abstract class AbstractEntityRepository implements EntityRepositoryInterface
41
{
42
    /**
43
     * @var string
44
     */
45
    protected static $alias;
46
    /**
47
     * @var EntityManagerInterface
48
     */
49
    protected $entityManager;
50
    /**
51
     * @var EntityRepository
52
     */
53
    protected $entityRepository;
54
    /**
55
     * @var string
56
     */
57
    protected $repositoryFactoryFqn;
58
    /**
59
     * @var ClassMetadata|null
60
     */
61
    protected $metaData;
62
    /**
63
     * @var NamespaceHelper
64
     */
65
    protected $namespaceHelper;
66
    /**
67
     * @var EntityFactoryInterface
68
     */
69
    private $entityFactory;
70
71
    /**
72
     * AbstractEntityRepositoryFactory constructor.
73
     *
74
     * @param EntityManagerInterface $entityManager
75
     * @param EntityFactoryInterface $entityFactory
76
     * @param NamespaceHelper|null   $namespaceHelper
77
     */
78 11
    public function __construct(
79
        EntityManagerInterface $entityManager,
80
        EntityFactoryInterface $entityFactory,
81
        NamespaceHelper $namespaceHelper
82
    ) {
83 11
        $this->entityManager   = $entityManager;
84 11
        $this->namespaceHelper = $namespaceHelper;
85 11
        $this->entityFactory   = $entityFactory;
86 11
        $this->initRepository();
87 11
    }
88
89 11
    protected function initRepository(): void
90
    {
91 11
        if (null === $this->metaData) {
92 11
            $entityFqn      = $this->getEntityFqn();
93 11
            $this->metaData = $this->entityManager->getClassMetadata($entityFqn);
94
        }
95
96 11
        $this->entityRepository = new EntityRepository($this->entityManager, $this->metaData);
97 11
    }
98
99 11
    protected function getEntityFqn(): string
100
    {
101 11
        return '\\' . \str_replace(
102
                [
103 11
                    'Entity\\Repositories',
104
                ],
105
                [
106 11
                    'Entities',
107
                ],
108 11
                $this->namespaceHelper->cropSuffix(static::class, 'Repository')
109
            );
110
    }
111
112
    public function getRandomResultFromQueryBuilder(QueryBuilder $queryBuilder, string $entityAlias): ?EntityInterface
113
    {
114
        $count = $this->getCountForQueryBuilder($queryBuilder, $entityAlias);
115
        if (0 === $count) {
116
            return null;
117
        }
118
119
        $queryBuilder->setMaxResults(1);
120
        $limitIndex = random_int(0, $count - 1);
121
        $results    = $queryBuilder->getQuery()
122
                                   ->setFirstResult($limitIndex)
123
                                   ->execute();
124
        $entity     = current($results);
125
        if (null === $entity) {
126
            return null;
127
        }
128
        $this->initialiseEntity($entity);
129
130
        return $entity;
131
    }
132
133
    public function getCountForQueryBuilder(QueryBuilder $queryBuilder, string $aliasToCount): int
134
    {
135
        $clone = clone $queryBuilder;
136
        $clone->select($queryBuilder->expr()->count($aliasToCount));
137
138
        return (int)$clone->getQuery()->getSingleScalarResult();
139
    }
140
141 3
    public function initialiseEntity(EntityInterface $entity)
142
    {
143 3
        $this->entityFactory->initialiseEntity($entity);
144
145 3
        return $entity;
146
    }
147
148
    /**
149
     * @return array|EntityInterface[]
150
     */
151 2
    public function findAll(): array
152
    {
153 2
        return $this->initialiseEntities($this->entityRepository->findAll());
154
    }
155
156 4
    public function initialiseEntities($entities)
157
    {
158 4
        foreach ($entities as $entity) {
159 3
            $this->initialiseEntity($entity);
160
        }
161
162 4
        return $entities;
163
    }
164
165
    /**
166
     * @param mixed    $id
167
     * @param int|null $lockMode
168
     * @param int|null $lockVersion
169
     *
170
     * @return EntityInterface
171
     * @throws DoctrineStaticMetaException
172
     */
173 2
    public function get($id, ?int $lockMode = null, ?int $lockVersion = null)
174
    {
175
        try {
176 2
            $entity = $this->find($id, $lockMode, $lockVersion);
177 1
        } catch (ConversionException $e) {
178 1
            $error = 'Failed getting by id ' . $id
179 1
                     . ', unless configured as an int ID entity, this should be a valid UUID';
180 1
            throw new DoctrineStaticMetaException($error, $e->getCode(), $e);
181
        }
182 1
        if ($entity === null) {
183
            throw new DoctrineStaticMetaException('Could not find the entity with id ' . $id);
184
        }
185
186 1
        return $this->initialiseEntity($entity);
187
    }
188
189
    /**
190
     * @param mixed    $id
191
     * @param int|null $lockMode
192
     * @param int|null $lockVersion
193
     *
194
     * @return EntityInterface|null
195
     */
196 2
    public function find($id, ?int $lockMode = null, ?int $lockVersion = null)
197
    {
198 2
        $entity = $this->entityRepository->find($id, $lockMode, $lockVersion);
199 1
        if (null === $entity) {
200
            return null;
201
        }
202 1
        if ($entity instanceof EntityInterface) {
203 1
            $this->initialiseEntity($entity);
204
205 1
            return $entity;
206
        }
207
    }
208
209
    /**
210
     * @param array      $criteria
211
     * @param array|null $orderBy
212
     *
213
     * @return EntityInterface
214
     */
215
    public function getOneBy(array $criteria, ?array $orderBy = null)
216
    {
217
        $result = $this->findOneBy($criteria, $orderBy);
218
        if ($result === null) {
219
            throw new \RuntimeException('Could not find the entity');
220
        }
221
222
        return $this->initialiseEntity($result);
223
    }
224
225
    /**
226
     * @param array      $criteria
227
     * @param array|null $orderBy
228
     *
229
     * @return EntityInterface|null
230
     */
231 2
    public function findOneBy(array $criteria, ?array $orderBy = null)
232
    {
233 2
        $criteria = $this->mapCriteriaSetUuidsToStrings($criteria);
234 2
        $entity   = $this->entityRepository->findOneBy($criteria, $orderBy);
235 2
        if (null === $entity) {
236 1
            return null;
237
        }
238 1
        if ($entity instanceof EntityInterface) {
239 1
            $this->initialiseEntity($entity);
240
241 1
            return $entity;
242
        }
243
    }
244
245 5
    public function mapCriteriaSetUuidsToStrings(array $criteria): array
246
    {
247 5
        foreach ($criteria as $property => $value) {
248 2
            if ($value instanceof EntityInterface) {
249
                $criteria[$property] = $value->getId();
250
            }
251 2
            if ($value instanceof UuidInterface) {
252 1
                $criteria[$property] = $value->toString();
253
            }
254
        }
255
256 5
        return $criteria;
257
    }
258
259
    /**
260
     * @param array $criteria
261
     *
262
     * @return EntityInterface|null
263
     */
264 1
    public function getRandomOneBy(array $criteria)
265
    {
266 1
        $found = $this->getRandomBy($criteria, 1);
267 1
        if ([] === $found) {
268
            throw new \RuntimeException('Failed finding any Entities with this criteria');
269
        }
270 1
        $entity = current($found);
271 1
        if ($entity instanceof EntityInterface) {
272 1
            return $entity;
273
        }
274
        throw new \RuntimeException('Unexpected Entity Type ' . get_class($entity));
275
    }
276
277
    /**
278
     * @param array $criteria
279
     *
280
     * @param int   $numToGet
281
     *
282
     * @return EntityInterface[]|array
283
     */
284 2
    public function getRandomBy(array $criteria, int $numToGet = 1): array
285
    {
286 2
        $count = $this->count($criteria);
287 2
        if (0 === $count) {
288
            return [];
289
        }
290 2
        $randOffset = rand(0, $count - $numToGet);
291
292 2
        return $this->findBy($criteria, null, $numToGet, $randOffset);
293
    }
294
295 3
    public function count(array $criteria = []): int
296
    {
297 3
        $criteria = $this->mapCriteriaSetUuidsToStrings($criteria);
298
299 3
        return $this->entityRepository->count($criteria);
300
    }
301
302
    /**
303
     * @return array|EntityInterface[]
304
     */
305 3
    public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
306
    {
307 3
        $criteria = $this->mapCriteriaSetUuidsToStrings($criteria);
308
309 3
        return $this->initialiseEntities($this->entityRepository->findBy($criteria, $orderBy, $limit, $offset));
310
    }
311
312 1
    public function matching(Criteria $criteria): LazyCriteriaCollection
313
    {
314 1
        $collection = $this->entityRepository->matching($criteria);
315 1
        if ($collection instanceof LazyCriteriaCollection) {
0 ignored issues
show
introduced by
$collection is always a sub-type of Doctrine\ORM\LazyCriteriaCollection.
Loading history...
316 1
            return $this->initialiseEntities($collection);
317
        }
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 315 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...
318
    }
319
320 1
    public function createResultSetMappingBuilder(string $alias): Query\ResultSetMappingBuilder
321
    {
322 1
        return $this->entityRepository->createResultSetMappingBuilder($alias);
323
    }
324
325
    public function createNamedQuery(string $queryName): Query
326
    {
327
        return $this->entityRepository->createNamedQuery($queryName);
328
    }
329
330
    public function createNativeNamedQuery(string $queryName): NativeQuery
331
    {
332
        return $this->entityRepository->createNativeNamedQuery($queryName);
333
    }
334
335 1
    public function clear(): void
336
    {
337 1
        $this->entityRepository->clear();
338 1
    }
339
340
    /**
341
     * Create a query builder with the alias preset
342
     *
343
     * @param string|null $indexBy
344
     *
345
     * @return QueryBuilder
346
     */
347 1
    public function createQueryBuilderWithAlias(string $indexBy = null): QueryBuilder
348
    {
349 1
        return $this->createQueryBuilder($this->getAlias(), $indexBy);
350
    }
351
352 3
    public function createQueryBuilder(string $alias, string $indexBy = null): QueryBuilder
353
    {
354 3
        return (new UuidQueryBuilder($this->entityManager))
355 3
            ->select($alias)
356 3
            ->from($this->getClassName(), $alias, $indexBy);
357
    }
358
359 5
    public function getClassName(): string
360
    {
361 5
        return $this->entityRepository->getClassName();
362
    }
363
364
    /**
365
     * Generate an alias based on the class name
366
     *
367
     * removes the words entity and repository
368
     *
369
     * gets all the upper case letters and returns them as a lower case string
370
     *
371
     * Warning - nothing is done to guarantee uniqueness for now
372
     *
373
     * @return string
374
     */
375 2
    public function getAlias(): string
376
    {
377 2
        if (null !== static::$alias) {
0 ignored issues
show
introduced by
The condition null !== static::alias is always true.
Loading history...
378 2
            return static::$alias;
379
        }
380 1
        $class           = $this->namespaceHelper->getClassShortName($this->getClassName());
381 1
        $removeStopWords = str_ireplace(['entity', 'repository'], '', $class);
382 1
        $ucOnly          = preg_replace('%[^A-Z]%', '', $removeStopWords);
383
384 1
        static::$alias = strtolower($ucOnly);
385
386 1
        return static::$alias;
387
    }
388
389 1
    public function createDeletionQueryBuilderWithAlias(): QueryBuilder
390
    {
391 1
        return $this->createDeletionQueryBuilder($this->getAlias());
392
    }
393
394 1
    public function createDeletionQueryBuilder(string $alias): QueryBuilder
395
    {
396 1
        return (new UuidQueryBuilder($this->entityManager))
397 1
            ->delete($this->getClassName(), $alias);
398
    }
399
400
    /**
401
     * For use with query builder, auto prefix alias
402
     *
403
     * @param string $property
404
     *
405
     * @return string
406
     */
407 1
    public function aliasPrefix(string $property): string
408
    {
409 1
        return $this->getAlias() . '.' . $property;
410
    }
411
}
412