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 ( 08e101...6f7bef )
by joseph
23:56 queued 01:38
created

getRandomResultFromQueryBuilder()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 3
eloc 13
c 2
b 0
f 1
nc 3
nop 2
dl 0
loc 19
rs 9.8333
ccs 0
cts 17
cp 0
crap 12
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
    public function __construct(
79
        EntityManagerInterface $entityManager,
80
        EntityFactoryInterface $entityFactory,
81
        NamespaceHelper $namespaceHelper
82
    ) {
83
        $this->entityManager   = $entityManager;
84
        $this->namespaceHelper = $namespaceHelper;
85
        $this->entityFactory   = $entityFactory;
86
        $this->initRepository();
87
    }
88
89
    protected function initRepository(): void
90
    {
91
        if (null === $this->metaData) {
92
            $entityFqn      = $this->getEntityFqn();
93
            $this->metaData = $this->entityManager->getClassMetadata($entityFqn);
94
        }
95
96
        $this->entityRepository = new EntityRepository($this->entityManager, $this->metaData);
97
    }
98
99
    protected function getEntityFqn(): string
100
    {
101
        return '\\' . \str_replace(
102
                [
103
                    'Entity\\Repositories',
104
                ],
105
                [
106
                    'Entities',
107
                ],
108
                $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
    public function initialiseEntity(EntityInterface $entity)
142
    {
143
        $this->entityFactory->initialiseEntity($entity);
144
145
        return $entity;
146
    }
147
148
    /**
149
     * @return array|EntityInterface[]
150
     */
151
    public function findAll(): array
152
    {
153
        return $this->initialiseEntities($this->entityRepository->findAll());
154
    }
155
156
    public function initialiseEntities($entities)
157
    {
158
        foreach ($entities as $entity) {
159
            $this->initialiseEntity($entity);
160
        }
161
162
        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
    public function get($id, ?int $lockMode = null, ?int $lockVersion = null)
174
    {
175
        try {
176
            $entity = $this->find($id, $lockMode, $lockVersion);
177
        } catch (ConversionException $e) {
178
            $error = 'Failed getting by id ' . $id
179
                     . ', unless configured as an int ID entity, this should be a valid UUID';
180
            throw new DoctrineStaticMetaException($error, $e->getCode(), $e);
181
        }
182
        if ($entity === null) {
183
            throw new DoctrineStaticMetaException('Could not find the entity with id ' . $id);
184
        }
185
186
        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
    public function find($id, ?int $lockMode = null, ?int $lockVersion = null)
197
    {
198
        $entity = $this->entityRepository->find($id, $lockMode, $lockVersion);
199
        if (null === $entity) {
200
            return null;
201
        }
202
        if ($entity instanceof EntityInterface) {
203
            $this->initialiseEntity($entity);
204
205
            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
    public function findOneBy(array $criteria, ?array $orderBy = null)
232
    {
233
        $criteria = $this->mapCriteriaSetUuidsToStrings($criteria);
234
        $entity   = $this->entityRepository->findOneBy($criteria, $orderBy);
235
        if (null === $entity) {
236
            return null;
237
        }
238
        if ($entity instanceof EntityInterface) {
239
            $this->initialiseEntity($entity);
240
241
            return $entity;
242
        }
243
    }
244
245
    public function mapCriteriaSetUuidsToStrings(array $criteria): array
246
    {
247
        foreach ($criteria as $property => $value) {
248
            if ($value instanceof EntityInterface) {
249
                $criteria[$property] = $value->getId();
250
            }
251
            if ($value instanceof UuidInterface) {
252
                $criteria[$property] = $value->toString();
253
            }
254
        }
255
256
        return $criteria;
257
    }
258
259
    /**
260
     * @param array $criteria
261
     *
262
     * @return EntityInterface|null
263
     */
264
    public function getRandomOneBy(array $criteria)
265
    {
266
        $found = $this->getRandomBy($criteria, 1);
267
        if ([] === $found) {
268
            throw new \RuntimeException('Failed finding any Entities with this criteria');
269
        }
270
        $entity = current($found);
271
        if ($entity instanceof EntityInterface) {
272
            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
    public function getRandomBy(array $criteria, int $numToGet = 1): array
285
    {
286
        $count = $this->count($criteria);
287
        if (0 === $count) {
288
            return [];
289
        }
290
        $randOffset = rand(0, $count - $numToGet);
291
292
        return $this->findBy($criteria, null, $numToGet, $randOffset);
293
    }
294
295
    public function count(array $criteria = []): int
296
    {
297
        $criteria = $this->mapCriteriaSetUuidsToStrings($criteria);
298
299
        return $this->entityRepository->count($criteria);
300
    }
301
302
    /**
303
     * @return array|EntityInterface[]
304
     */
305
    public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
306
    {
307
        $criteria = $this->mapCriteriaSetUuidsToStrings($criteria);
308
309
        return $this->initialiseEntities($this->entityRepository->findBy($criteria, $orderBy, $limit, $offset));
310
    }
311
312
    public function matching(Criteria $criteria): LazyCriteriaCollection
313
    {
314
        $collection = $this->entityRepository->matching($criteria);
315
        if ($collection instanceof LazyCriteriaCollection) {
0 ignored issues
show
introduced by
$collection is always a sub-type of Doctrine\ORM\LazyCriteriaCollection.
Loading history...
316
            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
    public function createResultSetMappingBuilder(string $alias): Query\ResultSetMappingBuilder
321
    {
322
        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
    public function clear(): void
336
    {
337
        $this->entityRepository->clear();
338
    }
339
340
    /**
341
     * Create a query builder with the alias preset
342
     *
343
     * @param string|null $indexBy
344
     *
345
     * @return QueryBuilder
346
     */
347
    public function createQueryBuilderWithAlias(string $indexBy = null): QueryBuilder
348
    {
349
        return $this->createQueryBuilder($this->getAlias(), $indexBy);
350
    }
351
352
    public function createQueryBuilder(string $alias, string $indexBy = null): QueryBuilder
353
    {
354
        #return $this->entityRepository->createQueryBuilder($alias, $indexBy);
355
        return (new UuidQueryBuilder($this->entityManager))
356
            ->select($alias)
357
            ->from($this->getClassName(), $alias, $indexBy);
358
    }
359
360
    public function getClassName(): string
361
    {
362
        return $this->entityRepository->getClassName();
363
    }
364
365
    /**
366
     * Generate an alias based on the class name
367
     *
368
     * removes the words entity and repository
369
     *
370
     * gets all the upper case letters and returns them as a lower case string
371
     *
372
     * Warning - nothing is done to guarantee uniqueness for now
373
     *
374
     * @return string
375
     */
376
    public function getAlias(): string
377
    {
378
        if (null !== static::$alias) {
0 ignored issues
show
introduced by
The condition null !== static::alias is always true.
Loading history...
379
            return static::$alias;
380
        }
381
        $class           = $this->namespaceHelper->getClassShortName($this->getClassName());
382
        $removeStopWords = str_ireplace(['entity', 'repository'], '', $class);
383
        $ucOnly          = preg_replace('%[^A-Z]%', '', $removeStopWords);
384
385
        static::$alias = strtolower($ucOnly);
386
387
        return static::$alias;
388
    }
389
390
    /**
391
     * For use with query builder, auto prefix alias
392
     *
393
     * @param string $property
394
     *
395
     * @return string
396
     */
397
    public function aliasPrefix(string $property): string
398
    {
399
        return $this->getAlias() . '.' . $property;
400
    }
401
}
402