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 ( a22100...0c1d55 )
by joseph
20s queued 15s
created

TestEntityGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1.125

Importance

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