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

getTestEntityGeneratorFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
ccs 0
cts 3
cp 0
crap 2
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\CodeGeneration\NamespaceHelper;
10
use EdmondsCommerce\DoctrineStaticMeta\DoctrineStaticMeta;
11
use EdmondsCommerce\DoctrineStaticMeta\Entity\DataTransferObjects\DtoFactory;
12
use EdmondsCommerce\DoctrineStaticMeta\Entity\Factory\EntityFactoryInterface;
13
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\DataTransferObjectInterface;
14
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\EntityInterface;
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
68
    /**
69
     * TestEntityGenerator constructor.
70
     *
71
     * @param DoctrineStaticMeta          $testedEntityDsm
72
     * @param EntityFactoryInterface|null $entityFactory
73
     * @param DtoFactory                  $dtoFactory
74
     * @param TestEntityGeneratorFactory  $testEntityGeneratorFactory
75
     * @param FakerDataFillerInterface    $fakerDataFiller
76
     * @param EntityManagerInterface      $entityManager
77
     * @SuppressWarnings(PHPMD.StaticAccess)
78
     */
79
    public function __construct(
80
        DoctrineStaticMeta $testedEntityDsm,
81
        EntityFactoryInterface $entityFactory,
82
        DtoFactory $dtoFactory,
83
        TestEntityGeneratorFactory $testEntityGeneratorFactory,
84
        FakerDataFillerInterface $fakerDataFiller,
85
        EntityManagerInterface $entityManager
86
    ) {
87
        $this->testedEntityDsm            = $testedEntityDsm;
88
        $this->entityFactory              = $entityFactory;
89
        $this->dtoFactory                 = $dtoFactory;
90
        $this->testEntityGeneratorFactory = $testEntityGeneratorFactory;
91
        $this->fakerDataFiller            = $fakerDataFiller;
92
        $this->entityManager              = $entityManager;
93
    }
94
95
96
    public function assertSameEntityManagerInstance(EntityManagerInterface $entityManager): void
97
    {
98
        if ($entityManager === $this->entityManager) {
99
            return;
100
        }
101
        throw new RuntimeException('EntityManager instance is not the same as the one loaded in this factory');
102
    }
103
104
    /**
105
     * Use the factory to generate a new Entity, possibly with values set as well
106
     *
107
     * @param array $values
108
     *
109
     * @return EntityInterface
110
     */
111
    public function create(array $values = []): EntityInterface
112
    {
113
        $dto = $this->dtoFactory->createEmptyDtoFromEntityFqn($this->testedEntityDsm->getReflectionClass()->getName());
114
        if ([] !== $values) {
115
            foreach ($values as $property => $value) {
116
                $setter = 'set' . $property;
117
                $dto->$setter($value);
118
            }
119
        }
120
121
        return $this->entityFactory->create(
122
            $this->testedEntityDsm->getReflectionClass()->getName(),
123
            $dto
124
        );
125
    }
126
127
    /**
128
     * Generate an Entity. Optionally provide an offset from the first entity
129
     *
130
     * @return EntityInterface
131
     * @SuppressWarnings(PHPMD.StaticAccess)
132
     */
133
    public function generateEntity(): EntityInterface
134
    {
135
        return $this->createEntityWithData();
136
    }
137
138
    private function createEntityWithData(): EntityInterface
139
    {
140
        $dto = $this->generateDto();
141
142
        return $this->entityFactory->create($this->testedEntityDsm->getReflectionClass()->getName(), $dto);
143
    }
144
145
    public function generateDto(): DataTransferObjectInterface
146
    {
147
        $dto = $this->dtoFactory->createEmptyDtoFromEntityFqn(
148
            $this->testedEntityDsm->getReflectionClass()->getName()
149
        );
150
        $this->fakerUpdateDto($dto);
151
152
        return $dto;
153
    }
154
155
    public function fakerUpdateDto(DataTransferObjectInterface $dto): void
156
    {
157
        $this->fakerDataFiller->updateDtoWithFakeData($dto);
158
    }
159
160
    /**
161
     * @param EntityInterface $generated
162
     *
163
     * @throws ErrorException
164
     * @SuppressWarnings(PHPMD.ElseExpression)
165
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
166
     */
167
    public function addAssociationEntities(
168
        EntityInterface $generated
169
    ): void {
170
        $testedEntityReflection = $this->testedEntityDsm->getReflectionClass();
171
        $class                  = $testedEntityReflection->getName();
172
        $meta                   = $this->testedEntityDsm->getMetaData();
173
        $mappings               = $meta->getAssociationMappings();
174
        if (empty($mappings)) {
175
            return;
176
        }
177
        $namespaceHelper = new NamespaceHelper();
178
        $methods         = array_map('strtolower', get_class_methods($generated));
179
        foreach ($mappings as $mapping) {
180
            $mappingEntityFqn                     = $mapping['targetEntity'];
181
            $errorMessage                         = "Error adding association entity $mappingEntityFqn to $class: %s";
182
            $mappingEntityPluralInterface         =
183
                $namespaceHelper->getHasPluralInterfaceFqnForEntity($mappingEntityFqn);
184
            $mappingEntityPluralInterfaceRequired =
185
                str_replace('\\Has', '\\HasRequired', $mappingEntityPluralInterface);
186
            if (
187
                (interface_exists($mappingEntityPluralInterface)
188
                 && $testedEntityReflection->implementsInterface($mappingEntityPluralInterface)
189
                )
190
                ||
191
                (interface_exists($mappingEntityPluralInterfaceRequired)
192
                 && $testedEntityReflection->implementsInterface($mappingEntityPluralInterfaceRequired)
193
                )
194
            ) {
195
                $this->assertSame(
196
                    $mappingEntityFqn::getDoctrineStaticMeta()->getPlural(),
197
                    $mapping['fieldName'],
198
                    sprintf($errorMessage, ' mapping should be plural')
199
                );
200
                $getter = 'get' . $mappingEntityFqn::getDoctrineStaticMeta()->getPlural();
201
                $method = 'add' . $mappingEntityFqn::getDoctrineStaticMeta()->getSingular();
202
            } else {
203
                $this->assertSame(
204
                    $mappingEntityFqn::getDoctrineStaticMeta()->getSingular(),
205
                    $mapping['fieldName'],
206
                    sprintf($errorMessage, ' mapping should be singular')
207
                );
208
                $getter = 'get' . $mappingEntityFqn::getDoctrineStaticMeta()->getSingular();
209
                $method = 'set' . $mappingEntityFqn::getDoctrineStaticMeta()->getSingular();
210
            }
211
            $this->assertInArray(
212
                strtolower($method),
213
                $methods,
214
                sprintf($errorMessage, $method . ' method is not defined')
215
            );
216
            try {
217
                $currentlySet = $generated->$getter();
218
            } catch (TypeError $e) {
219
                $currentlySet = null;
220
            }
221
            $this->addAssociation($generated, $method, $mappingEntityFqn, $currentlySet);
222
        }
223
    }
224
225
    /**
226
     * Stub of PHPUnit Assertion method
227
     *
228
     * @param mixed  $expected
229
     * @param mixed  $actual
230
     * @param string $error
231
     *
232
     * @throws ErrorException
233
     */
234
    protected function assertSame($expected, $actual, string $error): void
235
    {
236
        if ($expected !== $actual) {
237
            throw new ErrorException($error);
238
        }
239
    }
240
241
    /**
242
     * Stub of PHPUnit Assertion method
243
     *
244
     * @param mixed  $needle
245
     * @param array  $haystack
246
     * @param string $error
247
     *
248
     * @throws ErrorException
249
     */
250
    protected function assertInArray($needle, array $haystack, string $error): void
251
    {
252
        if (false === in_array($needle, $haystack, true)) {
253
            throw new ErrorException($error);
254
        }
255
    }
256
257
    private function addAssociation(
258
        EntityInterface $generated,
259
        string $setOrAddMethod,
260
        string $mappingEntityFqn,
261
        $currentlySet
262
    ): void {
263
        $testEntityGenerator = $this->testEntityGeneratorFactory
264
            ->createForEntityFqn($mappingEntityFqn);
265
        switch (true) {
266
            case $currentlySet === null:
267
            case $currentlySet === []:
268
            case $currentlySet instanceof Collection:
269
                $mappingEntity = $testEntityGenerator->createEntityRelatedToEntity($generated);
270
                break;
271
            default:
272
                return;
273
        }
274
        $generated->$setOrAddMethod($mappingEntity);
275
        $this->entityManager->persist($mappingEntity);
276
    }
277
278
    /**
279
     * @param EntityInterface $entity
280
     *
281
     * @return mixed
282
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod - it is being used)
283
     */
284
    private function createEntityRelatedToEntity(EntityInterface $entity)
285
    {
286
        $dto = $this->generateDtoRelatedToEntity($entity);
287
288
        return $this->entityFactory->create(
289
            $this->testedEntityDsm->getReflectionClass()->getName(),
290
            $dto
291
        );
292
    }
293
294
    public function generateDtoRelatedToEntity(EntityInterface $entity): DataTransferObjectInterface
295
    {
296
        $dto = $this->dtoFactory->createDtoRelatedToEntityInstance(
297
            $entity,
298
            $this->testedEntityDsm->getReflectionClass()->getName()
299
        );
300
        $this->fakerDataFiller->updateDtoWithFakeData($dto);
301
302
        return $dto;
303
    }
304
305
    /**
306
     * Generate Entities.
307
     *
308
     * Optionally discard the first generated entities up to the value of offset
309
     *
310
     * @param int $num
311
     *
312
     * @return array|EntityInterface[]
313
     */
314
    public function generateEntities(
315
        int $num
316
    ): array {
317
        $entities  = [];
318
        $generator = $this->getGenerator($num);
319
        foreach ($generator as $entity) {
320
            $id = (string)$entity->getId();
321
            if (array_key_exists($id, $entities)) {
322
                throw new RuntimeException('Entity with ID ' . $id . ' is already generated');
323
            }
324
            $entities[$id] = $entity;
325
        }
326
327
        return $entities;
328
    }
329
330
    public function getGenerator(int $numToGenerate = 100): Generator
331
    {
332
        $entityFqn = $this->testedEntityDsm->getReflectionClass()->getName();
333
        $generated = 0;
334
        while ($generated < $numToGenerate) {
335
            $dto    = $this->generateDto();
336
            $entity = $this->entityFactory->setEntityManager($this->entityManager)->create($entityFqn, $dto);
337
            yield $entity;
338
            $generated++;
339
        }
340
    }
341
342
    /**
343
     * @return EntityFactoryInterface
344
     */
345
    public function getEntityFactory(): EntityFactoryInterface
346
    {
347
        return $this->entityFactory;
348
    }
349
350
    /**
351
     * @return DtoFactory
352
     */
353
    public function getDtoFactory(): DtoFactory
354
    {
355
        return $this->dtoFactory;
356
    }
357
358
    /**
359
     * @return FakerDataFillerInterface
360
     */
361
    public function getFakerDataFiller(): FakerDataFillerInterface
362
    {
363
        return $this->fakerDataFiller;
364
    }
365
366
    /**
367
     * @return EntityManagerInterface
368
     */
369
    public function getEntityManager(): EntityManagerInterface
370
    {
371
        return $this->entityManager;
372
    }
373
374
    /**
375
     * @return TestEntityGeneratorFactory
376
     */
377
    public function getTestEntityGeneratorFactory(): TestEntityGeneratorFactory
378
    {
379
        return $this->testEntityGeneratorFactory;
380
    }
381
}
382