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 (#225)
by joseph
18:50
created

TestEntityGenerator::generateEntity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1.037

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 3
cp 0.6667
crap 1.037
rs 10
c 0
b 0
f 0
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 8
    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 8
        $this->testedEntityDsm            = $testedEntityDsm;
94 8
        $this->entityFactory              = $entityFactory;
95 8
        $this->dtoFactory                 = $dtoFactory;
96 8
        $this->testEntityGeneratorFactory = $testEntityGeneratorFactory;
97 8
        $this->fakerDataFiller            = $fakerDataFiller;
98 8
        $this->entityManager              = $entityManager;
99 8
        $this->relationshipHelper         = $relationshipHelper;
100 8
    }
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 2
    public function create(array $values = []): EntityInterface
119
    {
120 2
        $dto = $this->dtoFactory->createEmptyDtoFromEntityFqn($this->testedEntityDsm->getReflectionClass()->getName());
121 2
        if ([] !== $values) {
122 1
            foreach ($values as $property => $value) {
123 1
                $setter = 'set' . $property;
124 1
                $dto->$setter($value);
125
            }
126
        }
127
128 2
        return $this->entityFactory->create(
129 2
            $this->testedEntityDsm->getReflectionClass()->getName(),
130 2
            $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 3
    public function generateEntity(): EntityInterface
141
    {
142 3
        return $this->createEntityWithData();
143
    }
144
145 3
    private function createEntityWithData(): EntityInterface
146
    {
147 3
        $dto = $this->generateDto();
148
149 3
        return $this->entityFactory->create($this->testedEntityDsm->getReflectionClass()->getName(), $dto);
150
    }
151
152 6
    public function generateDto(): DataTransferObjectInterface
153
    {
154 6
        $dto = $this->dtoFactory->createEmptyDtoFromEntityFqn(
155 6
            $this->testedEntityDsm->getReflectionClass()->getName()
156
        );
157 6
        $this->fakerUpdateDto($dto);
158
159 6
        return $dto;
160
    }
161
162 6
    public function fakerUpdateDto(DataTransferObjectInterface $dto): void
163
    {
164 6
        $this->fakerDataFiller->updateDtoWithFakeData($dto);
165 6
    }
166
167
    /**
168
     * @param EntityInterface $generated
169
     *
170
     * @throws ErrorException
171
     * @SuppressWarnings(PHPMD.ElseExpression)
172
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
173
     */
174 1
    public function addAssociationEntities(
175
        EntityInterface $generated
176
    ): void {
177 1
        $testedEntityReflection = $this->testedEntityDsm->getReflectionClass();
178 1
        $class                  = $testedEntityReflection->getName();
179 1
        $meta                   = $this->testedEntityDsm->getMetaData();
180 1
        $mappings               = $meta->getAssociationMappings();
181 1
        if (empty($mappings)) {
182
            return;
183
        }
184 1
        $methods         = array_map('strtolower', get_class_methods($generated));
185 1
        $relationHelper  = $this->relationshipHelper;
186 1
        foreach ($mappings as $mapping) {
187 1
            $getter           = $relationHelper->getGetterFromDoctrineMapping($mapping);
188 1
            $isPlural         = $relationHelper->isPlural($mapping);
189
            $method           =
190 1
                ($isPlural) ? $relationHelper->getAdderFromDoctrineMapping($mapping) :
191 1
                    $relationHelper->getSetterFromDoctrineMapping($mapping);
192 1
            $mappingEntityFqn = $mapping['targetEntity'];
193 1
            $errorMessage     = "Error adding association entity $mappingEntityFqn to $class: %s";
194 1
            $this->assertInArray(
195 1
                strtolower($method),
196 1
                $methods,
197 1
                sprintf($errorMessage, $method . ' method is not defined')
198
            );
199
            try {
200 1
                $currentlySet = $generated->$getter();
201
            } catch (TypeError $e) {
202
                $currentlySet = null;
203
            }
204 1
            $this->addAssociation($generated, $method, $mappingEntityFqn, $currentlySet);
205
        }
206 1
    }
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 1
    protected function assertInArray($needle, array $haystack, string $error): void
234
    {
235 1
        if (false === in_array($needle, $haystack, true)) {
236
            throw new ErrorException($error);
237
        }
238 1
    }
239
240 1
    private function addAssociation(
241
        EntityInterface $generated,
242
        string $setOrAddMethod,
243
        string $mappingEntityFqn,
244
        $currentlySet
245
    ): void {
246 1
        $testEntityGenerator = $this->testEntityGeneratorFactory
247 1
            ->createForEntityFqn($mappingEntityFqn);
248 1
        switch (true) {
249
            case $currentlySet === null:
250 1
            case $currentlySet === []:
251 1
            case $currentlySet instanceof Collection:
252 1
                $mappingEntity = $testEntityGenerator->createEntityRelatedToEntity($generated);
253 1
                break;
254
            default:
255
                return;
256
        }
257 1
        $generated->$setOrAddMethod($mappingEntity);
258 1
        $this->entityManager->persist($mappingEntity);
259 1
    }
260
261
    /**
262
     * @param EntityInterface $entity
263
     *
264
     * @return mixed
265
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod - it is being used)
266
     */
267 1
    private function createEntityRelatedToEntity(EntityInterface $entity)
268
    {
269 1
        $dto = $this->generateDtoRelatedToEntity($entity);
270
271 1
        return $this->entityFactory->create(
272 1
            $this->testedEntityDsm->getReflectionClass()->getName(),
273 1
            $dto
274
        );
275
    }
276
277 1
    public function generateDtoRelatedToEntity(EntityInterface $entity): DataTransferObjectInterface
278
    {
279 1
        $dto = $this->dtoFactory->createDtoRelatedToEntityInstance(
280 1
            $entity,
281 1
            $this->testedEntityDsm->getReflectionClass()->getName()
282
        );
283 1
        $this->fakerDataFiller->updateDtoWithFakeData($dto);
284
285 1
        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 1
    public function generateEntities(
298
        int $num
299
    ): array {
300 1
        $entities  = [];
301 1
        $generator = $this->getGenerator($num);
302 1
        foreach ($generator as $entity) {
303 1
            $id = (string)$entity->getId();
304 1
            if (array_key_exists($id, $entities)) {
305
                throw new RuntimeException('Entity with ID ' . $id . ' is already generated');
306
            }
307 1
            $entities[$id] = $entity;
308
        }
309
310 1
        return $entities;
311
    }
312
313 3
    public function getGenerator(int $numToGenerate = 100): Generator
314
    {
315 3
        $entityFqn = $this->testedEntityDsm->getReflectionClass()->getName();
316 3
        $generated = 0;
317 3
        while ($generated < $numToGenerate) {
318 3
            $dto    = $this->generateDto();
319 3
            $entity = $this->entityFactory->setEntityManager($this->entityManager)->create($entityFqn, $dto);
320 3
            yield $entity;
321 3
            $generated++;
322
        }
323 2
    }
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