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 (#139)
by joseph
34:01 queued 31:09
created

EntityGenerator::getUseUuidPrimaryKey()   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 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 0
cts 2
cp 0
cc 1
nc 1
nop 0
crap 2
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator;
4
5
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\CodeHelper;
6
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field\IdTrait;
7
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
8
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\PathHelper;
9
use EdmondsCommerce\DoctrineStaticMeta\Config;
10
use EdmondsCommerce\DoctrineStaticMeta\Entity\Repositories\AbstractEntityRepository;
11
use EdmondsCommerce\DoctrineStaticMeta\Entity\Savers\AbstractEntitySpecificSaver;
12
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
13
use EdmondsCommerce\DoctrineStaticMeta\MappingHelper;
14
use gossi\codegen\model\PhpClass;
15
use gossi\codegen\model\PhpInterface;
16
use Symfony\Component\Filesystem\Filesystem;
17
18
/**
19
 * Class EntityGenerator
20
 *
21
 * @package EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator
22
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
23
 */
24
class EntityGenerator extends AbstractGenerator
25
{
26
    /**
27
     * @var IdTrait
28
     */
29
    protected $idTrait;
30
31
    public function __construct(
32
        Filesystem $filesystem,
33
        FileCreationTransaction $fileCreationTransaction,
34
        NamespaceHelper $namespaceHelper,
35
        Config $config,
36
        CodeHelper $codeHelper,
37
        PathHelper $pathHelper,
38
        FindAndReplaceHelper $findAndReplaceHelper,
39
        IdTrait $idTrait
40
    ) {
41
        parent::__construct(
42
            $filesystem,
43
            $fileCreationTransaction,
44
            $namespaceHelper,
45
            $config,
46
            $codeHelper,
47
            $pathHelper,
48
            $findAndReplaceHelper
49
        );
50
        $this->idTrait = $idTrait;
51
    }
52
53
    /**
54
     * @param string $entityFqn
55
     *
56
     * @param bool   $generateSpecificEntitySaver
57
     *
58
     * @return string - absolute path to created file
59
     * @throws DoctrineStaticMetaException
60
     * @SuppressWarnings(PHPMD.StaticAccess)
61
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
62
     */
63 4
    public function generateEntity(
64
        string $entityFqn,
65
        bool $generateSpecificEntitySaver = false
66
    ): string {
67
        try {
68 4
            if (false === \ts\stringContains($entityFqn, '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\')) {
69
                throw new \RuntimeException(
70
                    'Fully qualified name [' . $entityFqn
71
                    . '] does not include the Entities folder name ['
72
                    . AbstractGenerator::ENTITIES_FOLDER_NAME
73
                    . ']. Please ensure you pass in the full namespace qualified entity name'
74
                );
75
            }
76
77 4
            $shortName = MappingHelper::getShortNameForFqn($entityFqn);
78 4
            $plural    = MappingHelper::getPluralForFqn($entityFqn);
79 4
            $singular  = MappingHelper::getSingularForFqn($entityFqn);
80
81 4
            if (\strtolower($shortName) === $plural) {
82
                throw new \RuntimeException(
83
                    'Plural entity name used [' . $plural . ']. '
84
                    . 'Only singular entity names are allowed. '
85
                    . 'Please update this to [' . $singular . ']'
86
                );
87
            }
88
89 4
            $this->createEntityTest($entityFqn);
90 4
            $this->createEntityFixture($entityFqn);
91 4
            $this->createEntityRepository($entityFqn);
92 4
            $this->createEntityFactory($entityFqn);
93 4
            if (true === $generateSpecificEntitySaver) {
94
                $this->createEntitySaver($entityFqn);
95
            }
96
97 4
            $this->createInterface($entityFqn);
98
99 4
            return $this->createEntity($entityFqn);
100
        } catch (\Exception $e) {
101
            throw new DoctrineStaticMetaException(
102
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
103
                $e->getCode(),
104
                $e
105
            );
106
        }
107
    }
108
109
    /**
110
     * @param string $entityFullyQualifiedName
111
     *
112
     * @throws DoctrineStaticMetaException
113
     */
114
    protected function createEntityTest(string $entityFullyQualifiedName): void
115
    {
116
        try {
117
            $abstractTestPath = $this->pathToProjectRoot . '/'
118
                                . $this->testSubFolderName
119
                                . '/' . AbstractGenerator::ENTITIES_FOLDER_NAME
120
                                . '/AbstractEntityTest.php';
121
            if (!$this->getFilesystem()->exists($abstractTestPath)) {
122
                $this->getFilesystem()->copy(self::ABSTRACT_ENTITY_TEST_TEMPLATE_PATH, $abstractTestPath);
123
                $this->fileCreationTransaction::setPathCreated($abstractTestPath);
124
                $this->findAndReplaceHelper->findReplace(
125
                    self::FIND_PROJECT_NAMESPACE,
126
                    rtrim($this->projectRootNamespace, '\\'),
127
                    $abstractTestPath
128
                );
129
            }
130
131
            $phpunitBootstrapPath = $this->pathToProjectRoot . '/'
132
                                    . $this->testSubFolderName . '/bootstrap.php';
133
            if (!$this->getFilesystem()->exists($phpunitBootstrapPath)) {
134
                $this->getFilesystem()->copy(self::PHPUNIT_BOOTSTRAP_TEMPLATE_PATH, $phpunitBootstrapPath);
135
                $this->fileCreationTransaction::setPathCreated($phpunitBootstrapPath);
136
            }
137
138
            list($filePath, $className, $namespace) = $this->parseAndCreate(
139
                $entityFullyQualifiedName . 'Test',
140
                $this->testSubFolderName,
141
                self::ENTITY_TEST_TEMPLATE_PATH
142
            );
143
            $this->findAndReplaceHelper->findReplace(
144
                self::FIND_ENTITIES_NAMESPACE,
145
                $this->namespaceHelper->tidy($namespace),
146
                $filePath
147
            );
148
149
            $this->findAndReplaceHelper->replaceName($className, $filePath, self::FIND_ENTITY_NAME . 'Test');
150
            $this->findAndReplaceHelper->replaceProjectNamespace($this->projectRootNamespace, $filePath);
151
            $this->findAndReplaceHelper->replaceEntityRepositoriesNamespace($namespace, $filePath);
152
            $this->findAndReplaceHelper->findReplace(
153
                'use FQNFor\AbstractEntityTest;',
154
                'use ' . $this->namespaceHelper->tidy(
155
                    $this->projectRootNamespace
156
                    . '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME
157
                    . '\\AbstractEntityTest;'
158
                ),
159
                $filePath
160
            );
161
        } catch (\Exception $e) {
162
            throw new DoctrineStaticMetaException(
163
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
164
                $e->getCode(),
165
                $e
166
            );
167
        }
168
    }
169
170
    /**
171
     * @throws DoctrineStaticMetaException
172
     */
173
    protected function parseAndCreate(
174
        string $fullyQualifiedName,
175
        string $subDir,
176
        string $templatePath
177
    ): array {
178
        try {
179
            list($className, $namespace, $subDirectories) = $this->parseFullyQualifiedName(
180
                $fullyQualifiedName,
181
                $subDir
182
            );
183
            $filePath = $this->pathHelper->copyTemplateAndGetPath(
184
                $this->pathToProjectRoot,
185
                $templatePath,
186
                $className,
187
                $subDirectories
188
            );
189
190
            return [$filePath, $className, $this->namespaceHelper->tidy($namespace)];
191
        } catch (\Exception $e) {
192
            throw new DoctrineStaticMetaException(
193
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
194
                $e->getCode(),
195
                $e
196
            );
197
        }
198
    }
199
200
    protected function createEntityFixture(string $entityFullyQualifiedName): void
201
    {
202
203
        list($filePath, $className, $namespace) = $this->parseAndCreate(
204
            $this->namespaceHelper->getFixtureFqnFromEntityFqn($entityFullyQualifiedName),
205
            $this->testSubFolderName,
206
            self::ENTITY_FIXTURE_TEMPLATE_PATH
207
        );
208
        $this->findAndReplaceHelper->findReplace(
209
            'TemplateNamespace\Assets\EntityFixtures',
210
            $this->namespaceHelper->tidy($namespace),
211
            $filePath
212
        );
213
        $this->findAndReplaceHelper->replaceName($className, $filePath, self::FIND_ENTITY_NAME . 'Fixture');
214
        $this->findAndReplaceHelper->replaceProjectNamespace($this->projectRootNamespace, $filePath);
215
    }
216
217
    /**
218
     * @param string $entityFullyQualifiedName
219
     *
220
     * @throws DoctrineStaticMetaException
221
     */
222
    protected function createEntityRepository(string $entityFullyQualifiedName): void
223
    {
224
        try {
225
            $abstractRepositoryPath = $this->pathToProjectRoot
226
                                      . '/' . $this->srcSubFolderName
227
                                      . '/' . AbstractGenerator::ENTITY_REPOSITORIES_FOLDER_NAME
228
                                      . '/AbstractEntityRepository.php';
229
            if (!$this->getFilesystem()->exists($abstractRepositoryPath)) {
230
                $this->getFilesystem()->copy(
231
                    self::ABSTRACT_ENTITY_REPOSITORY_TEMPLATE_PATH,
232
                    $abstractRepositoryPath
233
                );
234
                $this->fileCreationTransaction::setPathCreated($abstractRepositoryPath);
235
                $this->findAndReplaceHelper->replaceEntityRepositoriesNamespace(
236
                    $this->projectRootNamespace . '\\'
237
                    . AbstractGenerator::ENTITY_REPOSITORIES_NAMESPACE,
238
                    $abstractRepositoryPath
239
                );
240
            }
241
            $entityRepositoryFqn = \str_replace(
242
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
243
                '\\' . AbstractGenerator::ENTITY_REPOSITORIES_NAMESPACE . '\\',
244
                $entityFullyQualifiedName
245
            ) . 'Repository';
246
247
            list($filePath, $className, $namespace) = $this->parseAndCreate(
248
                $entityRepositoryFqn,
249
                $this->srcSubFolderName,
250
                self::REPOSITORIES_TEMPLATE_PATH
251
            );
252
            $this->findAndReplaceHelper->findReplace(
253
                self::FIND_ENTITY_REPOSITORIES_NAMESPACE,
254
                $this->namespaceHelper->tidy($namespace),
255
                $filePath
256
            );
257
            $classInterfaceNamespace = \str_replace(
258
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
259
                '\\' . AbstractGenerator::ENTITY_INTERFACE_NAMESPACE . '\\',
260
                $entityFullyQualifiedName
261
            ) . 'Interface';
262
            $classInterface          = preg_replace('#Repository$#', 'Interface', $className);
263
264
            $this->findAndReplaceHelper->replaceEntityInterfaceNamespace($classInterfaceNamespace, $filePath);
265
            $this->findAndReplaceHelper->replaceName($className, $filePath, self::FIND_ENTITY_NAME . 'Repository');
266
            $this->findAndReplaceHelper->replaceProjectNamespace($this->projectRootNamespace, $filePath);
267
            $this->findAndReplaceHelper->replaceEntityRepositoriesNamespace($namespace, $filePath);
268
            $this->findAndReplaceHelper->replaceName($classInterface, $filePath, self::FIND_ENTITY_NAME . 'Interface');
269
            $this->findAndReplaceHelper->findReplace(
270
                'use FQNFor\AbstractEntityRepository;',
271
                'use ' . $this->namespaceHelper->tidy(
272
                    $this->projectRootNamespace
273
                    . '\\' . AbstractGenerator::ENTITY_REPOSITORIES_NAMESPACE
274
                    . '\\AbstractEntityRepository;'
275
                ),
276
                $filePath
277
            );
278
        } catch (\Exception $e) {
279
            throw new DoctrineStaticMetaException(
280
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
281
                $e->getCode(),
282
                $e
283
            );
284
        }
285
    }
286
287
    /**
288
     * @param string $entityFullyQualifiedName
289
     *
290
     * @throws DoctrineStaticMetaException
291
     */
292
    protected function createEntityFactory(string $entityFullyQualifiedName): void
293
    {
294
        try {
295
            $abstractFactoryPath = $this->pathToProjectRoot
296
                                   . '/' . $this->srcSubFolderName
297
                                   . '/' . AbstractGenerator::ENTITY_FACTORIES_FOLDER_NAME
298
                                   . '/AbstractEntityFactory.php';
299
            if (!$this->getFilesystem()->exists($abstractFactoryPath)) {
300
                $this->getFilesystem()->copy(
301
                    self::ABSTRACT_ENTITY_FACTORY_TEMPLATE_PATH,
302
                    $abstractFactoryPath
303
                );
304
                $this->fileCreationTransaction::setPathCreated($abstractFactoryPath);
305
                $this->findAndReplaceHelper->replaceEntityRepositoriesNamespace(
306
                    $this->projectRootNamespace . '\\'
307
                    . AbstractGenerator::ENTITY_FACTORIES_NAMESPACE,
308
                    $abstractFactoryPath
309
                );
310
            }
311
            $entityFactoryFqn = \str_replace(
312
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
313
                '\\' . AbstractGenerator::ENTITY_FACTORIES_NAMESPACE . '\\',
314
                $entityFullyQualifiedName
315
            ) . 'Factory';
316
317
            list($filePath, $className, $namespace) = $this->parseAndCreate(
318
                $entityFactoryFqn,
319
                $this->srcSubFolderName,
320
                self::FACTORIES_TEMPLATE_PATH
321
            );
322
            list($entityShortName, ,) = $this->parseFullyQualifiedName($entityFullyQualifiedName);
323
            $this->findAndReplaceHelper->findReplace(
324
                self::FIND_ENTITY_FACTORIES_NAMESPACE,
325
                $this->namespaceHelper->tidy($namespace),
326
                $filePath
327
            );
328
            $classInterfaceNamespace = \str_replace(
329
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
330
                '\\' . AbstractGenerator::ENTITY_INTERFACE_NAMESPACE . '\\',
331
                $entityFullyQualifiedName
332
            ) . 'Interface';
333
            $classInterface          = preg_replace('#Factory$#', 'Interface', $className);
334
            $this->findAndReplaceHelper->replaceEntitiesNamespace($entityFullyQualifiedName, $filePath);
335
            $this->findAndReplaceHelper->findReplace('EntityFqn', $entityFullyQualifiedName, $filePath);
336
            $this->findAndReplaceHelper->replaceName($entityShortName, $filePath, self::FIND_ENTITY_NAME);
337
            $this->findAndReplaceHelper->replaceEntityInterfaceNamespace($classInterfaceNamespace, $filePath);
338
            $this->findAndReplaceHelper->replaceName($className, $filePath, self::FIND_ENTITY_NAME . 'Factory');
339
            $this->findAndReplaceHelper->replaceProjectNamespace($this->projectRootNamespace, $filePath);
340
            $this->findAndReplaceHelper->replaceEntityRepositoriesNamespace($namespace, $filePath);
341
            $this->findAndReplaceHelper->replaceName($classInterface, $filePath, self::FIND_ENTITY_NAME . 'Interface');
342
            $this->findAndReplaceHelper->findReplace(
343
                'use FQNFor\AbstractEntityFactory;',
344
                'use ' . $this->namespaceHelper->tidy(
345
                    $this->projectRootNamespace
346
                    . '\\' . AbstractGenerator::ENTITY_FACTORIES_NAMESPACE
347
                    . '\\AbstractEntityFactory;'
348
                ),
349
                $filePath
350
            );
351
        } catch (\Exception $e) {
352
            throw new DoctrineStaticMetaException(
353
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
354
                $e->getCode(),
355
                $e
356
            );
357
        }
358
    }
359
360
    /**
361
     * Create an entity saver
362
     *
363
     * @param string $entityFqn
364
     *
365
     * @throws DoctrineStaticMetaException
366
     * @SuppressWarnings(PHPMD.StaticAccess)
367
     */
368
    protected function createEntitySaver(string $entityFqn): void
369
    {
370
        $entitySaverFqn = \str_replace(
371
            '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
372
            AbstractGenerator::ENTITY_SAVERS_NAMESPACE . '\\',
373
            $entityFqn
374
        ) . 'Saver';
375
376
377
        $entitySaver = new PhpClass();
378
        $entitySaver
379
            ->setQualifiedName($entitySaverFqn)
380
            ->setParentClassName('\\' . AbstractEntitySpecificSaver::class)
381
            ->setInterfaces(
382
                [
383
                    PhpInterface::fromFile(__DIR__ . '/../../Entity/Savers/EntitySaverInterface.php'),
384
                ]
385
            );
386
387
        list($className, , $subDirectories) = $this->parseFullyQualifiedName(
388
            $entitySaverFqn,
389
            $this->srcSubFolderName
390
        );
391
392
        $filePath = $this->createSubDirectoriesAndGetPath($subDirectories);
393
394
        $this->codeHelper->generate($entitySaver, $filePath . '/' . $className . '.php');
395
    }
396
397
    /**
398
     * @param string $entityFullyQualifiedName
399
     *
400
     * @throws DoctrineStaticMetaException
401
     * @throws \ReflectionException
402
     */
403
    protected function createInterface(string $entityFullyQualifiedName): void
404
    {
405
        $entityInterfaceFqn = \str_replace(
406
            '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
407
            '\\' . AbstractGenerator::ENTITY_INTERFACE_NAMESPACE . '\\',
408
            $entityFullyQualifiedName
409
        ) . 'Interface';
410
411
        list($className, $namespace, $subDirectories) = $this->parseFullyQualifiedName(
412
            $entityInterfaceFqn,
413
            $this->srcSubFolderName
414
        );
415
416
        $filePath = $this->pathHelper->copyTemplateAndGetPath(
417
            $this->pathToProjectRoot,
418
            self::ENTITY_INTERFACE_TEMPLATE_PATH,
419
            $className,
420
            $subDirectories
421
        );
422
423
        $this->findAndReplaceHelper->replaceName($className, $filePath, self::FIND_ENTITY_NAME . 'Interface');
424
        $this->findAndReplaceHelper->replaceEntityInterfaceNamespace($namespace, $filePath);
425
    }
426
427
    protected function createEntity(
428
        string $entityFullyQualifiedName
429
    ): string {
430
        list($filePath, $className, $namespace) = $this->parseAndCreate(
431
            $entityFullyQualifiedName,
432
            $this->srcSubFolderName,
433
            self::ENTITY_TEMPLATE_PATH
434
        );
435
        $this->findAndReplaceHelper->replaceName($className, $filePath, static::FIND_ENTITY_NAME);
436
        $this->findAndReplaceHelper->replaceEntitiesNamespace($namespace, $filePath);
437
        $this->findAndReplaceHelper->replaceEntityRepositoriesNamespace(
438
            \str_replace(
439
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME,
440
                '\\' . AbstractGenerator::ENTITY_REPOSITORIES_NAMESPACE,
441
                $namespace
442
            ),
443
            $filePath
444
        );
445
446
        $this->idTrait->updateEntity($filePath);
447
448
        $interfaceNamespace = \str_replace(
449
            '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME,
450
            '\\' . AbstractGenerator::ENTITY_INTERFACE_NAMESPACE,
451
            $namespace
452
        );
453
454
        $this->findAndReplaceHelper->replaceEntityInterfaceNamespace($interfaceNamespace, $filePath);
455
456
        return $filePath;
457
    }
458
459
    public function setPrimaryKeyType(int $idType): self
460
    {
461
        $this->idTrait->setIdTrait($idType);
462
463
        return $this;
464
    }
465
466
    /**
467
     * Create the abstract entity repository factory if it doesn't currently exist
468
     */
469
    protected function createAbstractEntityRepositoryFactory(): void
470
    {
471
        $abstractRepositoryFactoryPath = $this->pathToProjectRoot
472
                                         . '/' . $this->srcSubFolderName
473
                                         . '/' . AbstractGenerator::ENTITY_REPOSITORIES_FOLDER_NAME
474
                                         . '/AbstractEntityRepositoryFactory.php';
475
476
        if ($this->getFilesystem()->exists($abstractRepositoryFactoryPath)) {
477
            return;
478
        }
479
480
        $abstractFactoryFqn = $this->projectRootNamespace
481
                              . AbstractGenerator::ENTITY_REPOSITORIES_NAMESPACE
482
                              . '\\AbstractEntityRepositoryFactory';
483
484
        $abstractFactory = new PhpClass();
485
        $abstractFactory
486
            ->setUseStatements([AbstractEntityRepository::class . ' as DSMRepositoryFactory'])
487
            ->setQualifiedName($abstractFactoryFqn)
488
            ->setParentClassName('DSMRepositoryFactory');
489
490
        $this->codeHelper->generate($abstractFactory, $abstractRepositoryFactoryPath);
491
    }
492
}
493