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 ( 0d82f1...4042bf )
by joseph
20s queued 14s
created

TestEntityGenerator   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 325
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 5
Bugs 1 Features 0
Metric Value
eloc 103
dl 0
loc 325
ccs 0
cts 185
cp 0
rs 9.6
c 5
b 1
f 0
wmc 35

20 Methods

Rating   Name   Duplication   Size   Complexity  
A getTestEntityGeneratorFactory() 0 3 1
A getDtoFactory() 0 3 1
A getFakerDataFiller() 0 3 1
A assertSame() 0 4 2
A assertSameEntityManagerInstance() 0 6 2
A getEntityFactory() 0 3 1
A getEntityManager() 0 3 1
A generateDtoRelatedToEntity() 0 9 1
A generateEntities() 0 14 3
A addAssociation() 0 19 4
A create() 0 13 3
A fakerUpdateDto() 0 3 1
A assertInArray() 0 4 2
A generateDto() 0 8 1
A __construct() 0 16 1
A createEntityWithData() 0 5 1
A createEntityRelatedToEntity() 0 7 1
A addAssociationEntities() 0 31 5
A getGenerator() 0 9 2
A generateEntity() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace EdmondsCommerce\DoctrineStaticMeta\Entity\Testing\EntityGenerator;
6
7
use Doctrine\Common\Collections\Collection;
8
use Doctrine\ORM\EntityManagerInterface;
9
use EdmondsCommerce\DoctrineStaticMeta\DoctrineStaticMeta;
10
use EdmondsCommerce\DoctrineStaticMeta\Entity\DataTransferObjects\DtoFactory;
11
use EdmondsCommerce\DoctrineStaticMeta\Entity\Factory\EntityFactoryInterface;
12
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\DataTransferObjectInterface;
13
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\EntityInterface;
14
use EdmondsCommerce\DoctrineStaticMeta\RelationshipHelper;
15
use ErrorException;
16
use Generator;
17
use RuntimeException;
18
use TypeError;
19
20
use function in_array;
21
use function interface_exists;
22
23
/**
24
 * Class TestEntityGenerator
25
 *
26
 * This class handles utilising Faker to build up an Entity and then also possible build associated entities and handle
27
 * the association
28
 *
29
 * Unique columns are guaranteed to have a totally unique value in this particular process, but not between processes
30
 *
31
 * This Class provides you a few ways to generate test Entities, either in bulk or one at a time
32
 *ExcessiveClassComplexity
33
 *
34
 * @package EdmondsCommerce\DoctrineStaticMeta\Entity\Testing
35
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
36
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
37
 */
38
class TestEntityGenerator
39
{
40
    /**
41
     * @var EntityManagerInterface
42
     */
43
    protected $entityManager;
44
45
    /**
46
     * @var DoctrineStaticMeta
47
     */
48
    protected $testedEntityDsm;
49
50
    /**
51
     * @var EntityFactoryInterface
52
     */
53
    protected $entityFactory;
54
    /**
55
     * @var DtoFactory
56
     */
57
    private $dtoFactory;
58
    /**
59
     * @var TestEntityGeneratorFactory
60
     */
61
    private $testEntityGeneratorFactory;
62
    /**
63
     * @var FakerDataFillerInterface
64
     */
65
    private $fakerDataFiller;
66
    /**
67
     * @var RelationshipHelper
68
     */
69
    private $relationshipHelper;
70
71
72
    /**
73
     * TestEntityGenerator constructor.
74
     *
75
     * @param DoctrineStaticMeta          $testedEntityDsm
76
     * @param EntityFactoryInterface|null $entityFactory
77
     * @param DtoFactory                  $dtoFactory
78
     * @param TestEntityGeneratorFactory  $testEntityGeneratorFactory
79
     * @param FakerDataFillerInterface    $fakerDataFiller
80
     * @param EntityManagerInterface      $entityManager
81
     * @param RelationshipHelper          $relationshipHelper
82
     * @SuppressWarnings(PHPMD.StaticAccess)
83
     */
84
    public function __construct(
85
        DoctrineStaticMeta $testedEntityDsm,
86
        EntityFactoryInterface $entityFactory,
87
        DtoFactory $dtoFactory,
88
        TestEntityGeneratorFactory $testEntityGeneratorFactory,
89
        FakerDataFillerInterface $fakerDataFiller,
90
        EntityManagerInterface $entityManager,
91
        RelationshipHelper $relationshipHelper
92
    ) {
93
        $this->testedEntityDsm            = $testedEntityDsm;
94
        $this->entityFactory              = $entityFactory;
95
        $this->dtoFactory                 = $dtoFactory;
96
        $this->testEntityGeneratorFactory = $testEntityGeneratorFactory;
97
        $this->fakerDataFiller            = $fakerDataFiller;
98
        $this->entityManager              = $entityManager;
99
        $this->relationshipHelper         = $relationshipHelper;
100
    }
101
102
103
    public function assertSameEntityManagerInstance(EntityManagerInterface $entityManager): void
104
    {
105
        if ($entityManager === $this->entityManager) {
106
            return;
107
        }
108
        throw new RuntimeException('EntityManager instance is not the same as the one loaded in this factory');
109
    }
110
111
    /**
112
     * Use the factory to generate a new Entity, possibly with values set as well
113
     *
114
     * @param array $values
115
     *
116
     * @return EntityInterface
117
     */
118
    public function create(array $values = []): EntityInterface
119
    {
120
        $dto = $this->dtoFactory->createEmptyDtoFromEntityFqn($this->testedEntityDsm->getReflectionClass()->getName());
121
        if ([] !== $values) {
122
            foreach ($values as $property => $value) {
123
                $setter = 'set' . $property;
124
                $dto->$setter($value);
125
            }
126
        }
127
128
        return $this->entityFactory->create(
129
            $this->testedEntityDsm->getReflectionClass()->getName(),
130
            $dto
131
        );
132
    }
133
134
    /**
135
     * Generate an Entity. Optionally provide an offset from the first entity
136
     *
137
     * @return EntityInterface
138
     * @SuppressWarnings(PHPMD.StaticAccess)
139
     */
140
    public function generateEntity(): EntityInterface
141
    {
142
        return $this->createEntityWithData();
143
    }
144
145
    private function createEntityWithData(): EntityInterface
146
    {
147
        $dto = $this->generateDto();
148
149
        return $this->entityFactory->create($this->testedEntityDsm->getReflectionClass()->getName(), $dto);
150
    }
151
152
    public function generateDto(): DataTransferObjectInterface
153
    {
154
        $dto = $this->dtoFactory->createEmptyDtoFromEntityFqn(
155
            $this->testedEntityDsm->getReflectionClass()->getName()
156
        );
157
        $this->fakerUpdateDto($dto);
158
159
        return $dto;
160
    }
161
162
    public function fakerUpdateDto(DataTransferObjectInterface $dto): void
163
    {
164
        $this->fakerDataFiller->updateDtoWithFakeData($dto);
165
    }
166
167
    /**
168
     * @param EntityInterface $generated
169
     *
170
     * @throws ErrorException
171
     * @SuppressWarnings(PHPMD.ElseExpression)
172
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
173
     */
174
    public function addAssociationEntities(
175
        EntityInterface $generated
176
    ): void {
177
        $testedEntityReflection = $this->testedEntityDsm->getReflectionClass();
178
        $class                  = $testedEntityReflection->getName();
179
        $meta                   = $this->testedEntityDsm->getMetaData();
180
        $mappings               = $meta->getAssociationMappings();
181
        if (empty($mappings)) {
182
            return;
183
        }
184
        $methods         = array_map('strtolower', get_class_methods($generated));
185
        $relationHelper  = $this->relationshipHelper;
186
        foreach ($mappings as $mapping) {
187
            $getter           = $relationHelper->getGetterFromDoctrineMapping($mapping);
188
            $isPlural         = $relationHelper->isPlural($mapping);
189
            $method           =
190
                ($isPlural) ? $relationHelper->getAdderFromDoctrineMapping($mapping) :
191
                    $relationHelper->getSetterFromDoctrineMapping($mapping);
192
            $mappingEntityFqn = $mapping['targetEntity'];
193
            $errorMessage     = "Error adding association entity $mappingEntityFqn to $class: %s";
194
            $this->assertInArray(
195
                strtolower($method),
196
                $methods,
197
                sprintf($errorMessage, $method . ' method is not defined')
198
            );
199
            try {
200
                $currentlySet = $generated->$getter();
201
            } catch (TypeError $e) {
202
                $currentlySet = null;
203
            }
204
            $this->addAssociation($generated, $method, $mappingEntityFqn, $currentlySet);
205
        }
206
    }
207
208
    /**
209
     * Stub of PHPUnit Assertion method
210
     *
211
     * @param mixed  $expected
212
     * @param mixed  $actual
213
     * @param string $error
214
     *
215
     * @throws ErrorException
216
     */
217
    protected function assertSame($expected, $actual, string $error): void
218
    {
219
        if ($expected !== $actual) {
220
            throw new ErrorException($error);
221
        }
222
    }
223
224
    /**
225
     * Stub of PHPUnit Assertion method
226
     *
227
     * @param mixed  $needle
228
     * @param array  $haystack
229
     * @param string $error
230
     *
231
     * @throws ErrorException
232
     */
233
    protected function assertInArray($needle, array $haystack, string $error): void
234
    {
235
        if (false === in_array($needle, $haystack, true)) {
236
            throw new ErrorException($error);
237
        }
238
    }
239
240
    private function addAssociation(
241
        EntityInterface $generated,
242
        string $setOrAddMethod,
243
        string $mappingEntityFqn,
244
        $currentlySet
245
    ): void {
246
        $testEntityGenerator = $this->testEntityGeneratorFactory
247
            ->createForEntityFqn($mappingEntityFqn);
248
        switch (true) {
249
            case $currentlySet === null:
250
            case $currentlySet === []:
251
            case $currentlySet instanceof Collection:
252
                $mappingEntity = $testEntityGenerator->createEntityRelatedToEntity($generated);
253
                break;
254
            default:
255
                return;
256
        }
257
        $generated->$setOrAddMethod($mappingEntity);
258
        $this->entityManager->persist($mappingEntity);
259
    }
260
261
    /**
262
     * @param EntityInterface $entity
263
     *
264
     * @return mixed
265
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod - it is being used)
266
     */
267
    private function createEntityRelatedToEntity(EntityInterface $entity)
268
    {
269
        $dto = $this->generateDtoRelatedToEntity($entity);
270
271
        return $this->entityFactory->create(
272
            $this->testedEntityDsm->getReflectionClass()->getName(),
273
            $dto
274
        );
275
    }
276
277
    public function generateDtoRelatedToEntity(EntityInterface $entity): DataTransferObjectInterface
278
    {
279
        $dto = $this->dtoFactory->createDtoRelatedToEntityInstance(
280
            $entity,
281
            $this->testedEntityDsm->getReflectionClass()->getName()
282
        );
283
        $this->fakerDataFiller->updateDtoWithFakeData($dto);
284
285
        return $dto;
286
    }
287
288
    /**
289
     * Generate Entities.
290
     *
291
     * Optionally discard the first generated entities up to the value of offset
292
     *
293
     * @param int $num
294
     *
295
     * @return array|EntityInterface[]
296
     */
297
    public function generateEntities(
298
        int $num
299
    ): array {
300
        $entities  = [];
301
        $generator = $this->getGenerator($num);
302
        foreach ($generator as $entity) {
303
            $id = (string)$entity->getId();
304
            if (array_key_exists($id, $entities)) {
305
                throw new RuntimeException('Entity with ID ' . $id . ' is already generated');
306
            }
307
            $entities[$id] = $entity;
308
        }
309
310
        return $entities;
311
    }
312
313
    public function getGenerator(int $numToGenerate = 100): Generator
314
    {
315
        $entityFqn = $this->testedEntityDsm->getReflectionClass()->getName();
316
        $generated = 0;
317
        while ($generated < $numToGenerate) {
318
            $dto    = $this->generateDto();
319
            $entity = $this->entityFactory->setEntityManager($this->entityManager)->create($entityFqn, $dto);
320
            yield $entity;
321
            $generated++;
322
        }
323
    }
324
325
    /**
326
     * @return EntityFactoryInterface
327
     */
328
    public function getEntityFactory(): EntityFactoryInterface
329
    {
330
        return $this->entityFactory;
331
    }
332
333
    /**
334
     * @return DtoFactory
335
     */
336
    public function getDtoFactory(): DtoFactory
337
    {
338
        return $this->dtoFactory;
339
    }
340
341
    /**
342
     * @return FakerDataFillerInterface
343
     */
344
    public function getFakerDataFiller(): FakerDataFillerInterface
345
    {
346
        return $this->fakerDataFiller;
347
    }
348
349
    /**
350
     * @return EntityManagerInterface
351
     */
352
    public function getEntityManager(): EntityManagerInterface
353
    {
354
        return $this->entityManager;
355
    }
356
357
    /**
358
     * @return TestEntityGeneratorFactory
359
     */
360
    public function getTestEntityGeneratorFactory(): TestEntityGeneratorFactory
361
    {
362
        return $this->testEntityGeneratorFactory;
363
    }
364
}
365