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 (#153)
by joseph
18:59 queued 14s
created

Builder::finaliseBuild()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
ccs 0
cts 6
cp 0
crap 2
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\Builder;
4
5
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Action\CreateDtosForAllEntitiesAction;
6
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\CodeHelper;
7
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Embeddable\ArchetypeEmbeddableGenerator;
8
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Embeddable\EntityEmbeddableSetter;
9
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\EntityGenerator;
10
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field\EntityFieldSetter;
11
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field\FieldGenerator;
12
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\RelationsGenerator;
13
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
14
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\PostProcessor\CopyPhpstormMeta;
15
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\PostProcessor\EntityFormatter;
16
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\UnusedRelationsRemover;
17
use EdmondsCommerce\DoctrineStaticMeta\Config;
18
use gossi\codegen\model\PhpClass;
19
use gossi\codegen\model\PhpConstant;
20
use gossi\codegen\model\PhpInterface;
21
use gossi\codegen\model\PhpTrait;
22
use ts\Reflection\ReflectionClass;
23
24
/**
25
 * Class Builder
26
 *
27
 * @package EdmondsCommerce\DoctrineStaticMeta\Builder
28
 * @SuppressWarnings(PHPMD)
29
 */
30
class Builder
31
{
32
33
    /**
34
     * @var EntityGenerator
35
     */
36
    protected $entityGenerator;
37
    /**
38
     * @var FieldGenerator
39
     */
40
    protected $fieldGenerator;
41
    /**
42
     * @var EntityFieldSetter
43
     */
44
    protected $fieldSetter;
45
    /**
46
     * @var RelationsGenerator
47
     */
48
    protected $relationsGenerator;
49
    /**
50
     * @var ArchetypeEmbeddableGenerator
51
     */
52
    protected $archetypeEmbeddableGenerator;
53
    /**
54
     * @var EntityEmbeddableSetter
55
     */
56
    protected $embeddableSetter;
57
    /**
58
     * @var CodeHelper
59
     */
60
    protected $codeHelper;
61
    /**
62
     * @var UnusedRelationsRemover
63
     */
64
    protected $unusedRelationsRemover;
65
    /**
66
     * @var CreateDtosForAllEntitiesAction
67
     */
68
    private $dataTransferObjectsForAllEntitiesAction;
69
    /**
70
     * @var EntityFormatter
71
     */
72
    private $entityFormatter;
73
    /**
74
     * @var CopyPhpstormMeta
75
     */
76
    private $copyPhpstormMeta;
77
    /**
78
     * @var NamespaceHelper
79
     */
80
    private $namespaceHelper;
81
82
    public function __construct(
83
        EntityGenerator $entityGenerator,
84
        FieldGenerator $fieldGenerator,
85
        EntityFieldSetter $fieldSetter,
86
        RelationsGenerator $relationsGenerator,
87
        ArchetypeEmbeddableGenerator $archetypeEmbeddableGenerator,
88
        EntityEmbeddableSetter $embeddableSetter,
89
        CodeHelper $codeHelper,
90
        UnusedRelationsRemover $unusedRelationsRemover,
91
        CreateDtosForAllEntitiesAction $dataTransferObjectsForAllEntitiesAction,
92
        EntityFormatter $entityFormatter,
93
        Config $config,
94
        CopyPhpstormMeta $copyPhpstormMeta,
95
        NamespaceHelper $namespaceHelper
96
    ) {
97
        $this->entityGenerator                         = $entityGenerator;
98
        $this->fieldGenerator                          = $fieldGenerator;
99
        $this->fieldSetter                             = $fieldSetter;
100
        $this->relationsGenerator                      = $relationsGenerator;
101
        $this->archetypeEmbeddableGenerator            = $archetypeEmbeddableGenerator;
102
        $this->embeddableSetter                        = $embeddableSetter;
103
        $this->codeHelper                              = $codeHelper;
104
        $this->unusedRelationsRemover                  = $unusedRelationsRemover;
105
        $this->dataTransferObjectsForAllEntitiesAction = $dataTransferObjectsForAllEntitiesAction;
106
        $this->entityFormatter                         = $entityFormatter;
107
        $this->copyPhpstormMeta                        = $copyPhpstormMeta;
108
        $this->namespaceHelper                         = $namespaceHelper;
109
110
        $this->setPathToProjectRoot($config::getProjectRootDirectory());
111
    }
112
113
    public function setPathToProjectRoot(string $pathToProjectRoot): self
114
    {
115
        $this->entityGenerator->setPathToProjectRoot($pathToProjectRoot);
116
        $this->fieldGenerator->setPathToProjectRoot($pathToProjectRoot);
117
        $this->fieldSetter->setPathToProjectRoot($pathToProjectRoot);
118
        $this->relationsGenerator->setPathToProjectRoot($pathToProjectRoot);
119
        $this->archetypeEmbeddableGenerator->setPathToProjectRoot($pathToProjectRoot);
120
        $this->unusedRelationsRemover->setPathToProjectRoot($pathToProjectRoot);
121
        $this->dataTransferObjectsForAllEntitiesAction->setProjectRootDirectory($pathToProjectRoot);
122
        $this->embeddableSetter->setPathToProjectRoot($pathToProjectRoot);
123
        $this->entityFormatter->setPathToProjectRoot($pathToProjectRoot);
124
        $this->copyPhpstormMeta->setPathToProjectRoot($pathToProjectRoot);
125
126
        return $this;
127
    }
128
129
    /**
130
     * @return EntityGenerator
131
     */
132
    public function getEntityGenerator(): EntityGenerator
133
    {
134
        return $this->entityGenerator;
135
    }
136
137
    /**
138
     * @return FieldGenerator
139
     */
140
    public function getFieldGenerator(): FieldGenerator
141
    {
142
        return $this->fieldGenerator;
143
    }
144
145
    /**
146
     * @return EntityFieldSetter
147
     */
148
    public function getFieldSetter(): EntityFieldSetter
149
    {
150
        return $this->fieldSetter;
151
    }
152
153
    /**
154
     * @return RelationsGenerator
155
     */
156
    public function getRelationsGenerator(): RelationsGenerator
157
    {
158
        return $this->relationsGenerator;
159
    }
160
161
    /**
162
     * @return ArchetypeEmbeddableGenerator
163
     */
164
    public function getArchetypeEmbeddableGenerator(): ArchetypeEmbeddableGenerator
165
    {
166
        return $this->archetypeEmbeddableGenerator;
167
    }
168
169
    /**
170
     * @return EntityEmbeddableSetter
171
     */
172
    public function getEmbeddableSetter(): EntityEmbeddableSetter
173
    {
174
        return $this->embeddableSetter;
175
    }
176
177
    /**
178
     * Finalise build - run various steps to wrap up the build and tidy up the codebase
179
     *
180
     * @return Builder
181
     */
182
    public function finaliseBuild(): self
183
    {
184
        $this->dataTransferObjectsForAllEntitiesAction->run();
185
        $this->entityFormatter->run();
186
        $this->copyPhpstormMeta->run();
187
188
        return $this;
189
    }
190
191
    public function removeUnusedRelations(): void
192
    {
193
        $this->unusedRelationsRemover->run();
194
    }
195
196
    /**
197
     * @param array $entityFqns
198
     *
199
     * @return Builder
200
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
201
     */
202
    public function generateEntities(array $entityFqns): self
203
    {
204
        $this->setProjectRootNamespace(
205
            $this->namespaceHelper->getProjectNamespaceRootFromEntityFqn(
206
                current($entityFqns)
207
            )
208
        );
209
        foreach ($entityFqns as $entityFqn) {
210
            $this->entityGenerator->generateEntity($entityFqn);
211
        }
212
213
        return $this;
214
    }
215
216
    public function setProjectRootNamespace(string $projectRootNamespace): self
217
    {
218
        $this->entityGenerator->setProjectRootNamespace($projectRootNamespace);
219
        $this->fieldGenerator->setProjectRootNamespace($projectRootNamespace);
220
        $this->fieldSetter->setProjectRootNamespace($projectRootNamespace);
221
        $this->relationsGenerator->setProjectRootNamespace($projectRootNamespace);
222
        $this->archetypeEmbeddableGenerator->setProjectRootNamespace($projectRootNamespace);
223
        $this->dataTransferObjectsForAllEntitiesAction->setProjectRootNamespace($projectRootNamespace);
224
        $this->embeddableSetter->setProjectRootNamespace($projectRootNamespace);
225
        $this->unusedRelationsRemover->setProjectRootNamespace($projectRootNamespace);
226
227
        return $this;
228
    }
229
230
    /**
231
     * @param array $entityRelationEntity
232
     *
233
     * @return Builder
234
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
235
     */
236
    public function setEntityRelations(array $entityRelationEntity): self
237
    {
238
        foreach ($entityRelationEntity as list($owningEntityFqn, $hasType, $ownedEntityFqn)) {
239
            $this->relationsGenerator->setEntityHasRelationToEntity($owningEntityFqn, $hasType, $ownedEntityFqn);
240
        }
241
242
        return $this;
243
    }
244
245
    /**
246
     * @param array $fields
247
     *
248
     * @return array $traitFqns
249
     */
250
    public function generateFields(array $fields): array
251
    {
252
        $traitFqns = [];
253
        foreach ($fields as list($fieldFqn, $fieldType)) {
254
            try {
255
                $traitFqns[] = $this->fieldGenerator->generateField($fieldFqn, $fieldType);
256
            } catch (\Exception $e) {
257
                throw new \RuntimeException(
258
                    'Failed building field with $fieldFqn: ' . $fieldFqn . ' and $fieldType ' . $fieldType,
259
                    $e->getCode(),
260
                    $e
261
                );
262
            }
263
        }
264
265
        return $traitFqns;
266
    }
267
268
    /**
269
     * @param string $entityFqn
270
     * @param array  $fieldFqns
271
     *
272
     * @return Builder
273
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
274
     */
275
    public function setFieldsToEntity(string $entityFqn, array $fieldFqns): self
276
    {
277
        foreach ($fieldFqns as $fieldFqn) {
278
            $this->fieldSetter->setEntityHasField($entityFqn, $fieldFqn);
279
        }
280
281
        return $this;
282
    }
283
284
    /**
285
     * @param array $embeddables
286
     *
287
     * @return array $traitFqns
288
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
289
     * @throws \ReflectionException
290
     */
291
    public function generateEmbeddables(array $embeddables): array
292
    {
293
        $traitFqns = [];
294
        foreach ($embeddables as list($archetypeEmbeddableObjectFqn, $newEmbeddableObjectClassName)) {
295
            $traitFqns[] = $this->archetypeEmbeddableGenerator->createFromArchetype(
296
                $archetypeEmbeddableObjectFqn,
297
                $newEmbeddableObjectClassName
298
            );
299
        }
300
301
        return $traitFqns;
302
    }
303
304
    /**
305
     * @param string $entityFqn
306
     * @param array  $embeddableTraitFqns
307
     *
308
     * @return Builder
309
     */
310
    public function setEmbeddablesToEntity(string $entityFqn, array $embeddableTraitFqns): self
311
    {
312
        foreach ($embeddableTraitFqns as $embeddableTraitFqn) {
313
            $this->embeddableSetter->setEntityHasEmbeddable($entityFqn, $embeddableTraitFqn);
314
        }
315
316
        return $this;
317
    }
318
319
    public function setEnumOptionsOnInterface(string $interfaceFqn, array $options): void
320
    {
321
        $pathToInterface = (new ReflectionClass($interfaceFqn))->getFileName();
322
        $basename        = basename($pathToInterface);
323
        $classy          = substr($basename, 0, strpos($basename, 'FieldInterface'));
324
        $consty          = $this->codeHelper->consty($classy);
325
        $interface       = PhpInterface::fromFile($pathToInterface);
326
        $constants       = $interface->getConstants();
327
        $constants->map(function (PhpConstant $constant) use ($interface, $consty) {
328
            if (0 === strpos($constant->getName(), $consty . '_OPTION')) {
329
                $interface->removeConstant($constant);
330
            }
331
            if (0 === strpos($constant->getName(), 'DEFAULT')) {
332
                $interface->removeConstant($constant);
333
            }
334
        });
335
        $optionConsts = [];
336
        foreach ($options as $option) {
337
            $name           = \str_replace(
338
                '__',
339
                '_',
340
                $consty . '_OPTION_' . $this->codeHelper->consty(
341
                    \str_replace(' ', '_', $option)
342
                )
343
            );
344
            $optionConsts[] = 'self::' . $name;
345
            $constant       = new PhpConstant($name, $option);
346
            $interface->setConstant($constant);
347
        }
348
        $interface->setConstant(
349
            new PhpConstant(
350
                $consty . '_OPTIONS',
351
                '[' . implode(",\n", $optionConsts) . ']',
352
                true
353
            )
354
        );
355
        $interface->setConstant(
356
            new PhpConstant(
357
                'DEFAULT_' . $consty,
358
                current($optionConsts),
359
                true
360
            )
361
        );
362
        $this->codeHelper->generate($interface, $pathToInterface);
363
    }
364
365
    public function injectTraitInToClass(string $traitFqn, string $classFqn): void
366
    {
367
        $classFilePath = $this->getFileName($classFqn);
368
        $class         = PhpClass::fromFile($classFilePath);
369
        $trait         = PhpTrait::fromFile($this->getFileName($traitFqn));
370
        $traits        = $class->getTraits();
371
        $exists        = array_search($traitFqn, $traits, true);
372
        if ($exists !== false) {
373
            return;
374
        }
375
        $class->addTrait($trait);
376
        $this->codeHelper->generate($class, $classFilePath);
377
    }
378
379
    private function getFileName(string $typeFqn): string
380
    {
381
        $reflectionClass = new ReflectionClass($typeFqn);
382
383
        return $reflectionClass->getFileName();
384
    }
385
386
    public function extendInterfaceWithInterface(string $interfaceToExtendFqn, string $interfaceToAddFqn): void
387
    {
388
        $toExtendFilePath = $this->getFileName($interfaceToExtendFqn);
389
        $toExtend         = PhpInterface::fromFile($toExtendFilePath);
390
        $toAdd            = PhpInterface::fromFile($this->getFileName($interfaceToAddFqn));
391
        $exists           = $toExtend->getInterfaces()->contains($interfaceToAddFqn);
392
        if ($exists !== false) {
393
            return;
394
        }
395
        $toExtend->addInterface($toAdd);
396
        $this->codeHelper->generate($toExtend, $toExtendFilePath);
397
    }
398
399
    public function removeIdTraitFromClass(string $classFqn): void
400
    {
401
        $traitFqn = "DSM\\Fields\\Traits\\PrimaryKey\\IdFieldTrait";
402
        $this->removeTraitFromClass($classFqn, $traitFqn);
403
    }
404
405
    public function removeTraitFromClass(string $classFqn, string $traitFqn): void
406
    {
407
        $classPath = $this->getFileName($classFqn);
408
        $class     = PhpClass::fromFile($classPath);
409
        $traits    = $class->getTraits();
410
        if ($class->getUseStatements()->contains($traitFqn) === true) {
411
            $class->removeUseStatement($traitFqn);
412
        }
413
        $index = array_search($traitFqn, $traits, true);
414
        if ($index === false) {
415
            $shortNameParts = explode('\\', $traitFqn);
416
            $shortName      = (string)array_pop($shortNameParts);
417
            $index          = array_search($shortName, $traits, true);
418
        }
419
        if ($index === false) {
420
            return;
421
        }
422
        unset($traits[$index]);
423
        $reflectionClass = new ReflectionClass(PhpClass::class);
424
        $property        = $reflectionClass->getProperty('traits');
425
        $property->setAccessible(true);
426
        $property->setValue($class, $traits);
427
        $this->codeHelper->generate($class, $classPath);
428
    }
429
}
430