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 (#152)
by joseph
17:58
created

DbalFieldGenerator::interfacePostCopy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
ccs 0
cts 6
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field;
4
5
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
6
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\CodeHelper;
7
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\FileCreationTransaction;
8
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\FindAndReplaceHelper;
9
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\PathHelper;
10
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\TypeHelper;
11
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\UsesPHPMetaDataInterface;
12
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
13
use EdmondsCommerce\DoctrineStaticMeta\MappingHelper;
14
use gossi\codegen\model\PhpMethod;
15
use gossi\codegen\model\PhpParameter;
16
use gossi\codegen\model\PhpTrait;
17
use gossi\docblock\Docblock;
18
use gossi\docblock\tags\UnknownTag;
19
use Symfony\Component\Filesystem\Filesystem;
20
21
/**
22
 * Class DbalFieldGenerator
23
 *
24
 * @package  EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field
25
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
26
 * @SuppressWarnings(PHPMD.TooManyFields)
27
 * @internal - this is only accessed via CodeGeneration\Generator\Field\FieldGenerator
28
 */
29
class DbalFieldGenerator
30
{
31
    /**
32
     * @var string
33
     */
34
    protected $traitPath;
35
    /**
36
     * @var string
37
     */
38
    protected $interfacePath;
39
    /**
40
     * @var null|string
41
     */
42
    protected $phpType;
43
    /**
44
     * @var null
45
     */
46
    protected $defaultValue;
47
    /**
48
     * @var bool
49
     */
50
    protected $isUnique;
51
    /**
52
     * @var bool
53
     */
54
    protected $isNullable;
55
    /**
56
     * @var string
57
     */
58
    protected $dbalType;
59
    /**
60
     * @var Filesystem
61
     */
62
    protected $fileSystem;
63
    /**
64
     * @var CodeHelper
65
     */
66
    protected $codeHelper;
67
    /**
68
     * @var FileCreationTransaction
69
     */
70
    protected $fileCreationTransaction;
71
    /**
72
     * @var FindAndReplaceHelper
73
     */
74
    protected $findAndReplaceHelper;
75
    /**
76
     * @var string
77
     */
78
    protected $className;
79
    /**
80
     * @var TypeHelper
81
     */
82
    protected $typeHelper;
83
    /**
84
     * @var string
85
     */
86
    protected $traitNamespace;
87
    /**
88
     * @var string
89
     */
90
    protected $interfaceNamespace;
91
    /**
92
     * @var PathHelper
93
     */
94
    protected $pathHelper;
95
96
    public function __construct(
97
        Filesystem $fileSystem,
98
        CodeHelper $codeHelper,
99
        FileCreationTransaction $fileCreationTransaction,
100
        FindAndReplaceHelper $findAndReplaceHelper,
101
        TypeHelper $typeHelper,
102
        PathHelper $pathHelper
103
    ) {
104
        $this->fileSystem              = $fileSystem;
105
        $this->codeHelper              = $codeHelper;
106
        $this->fileCreationTransaction = $fileCreationTransaction;
107
        $this->findAndReplaceHelper    = $findAndReplaceHelper;
108
        $this->typeHelper              = $typeHelper;
109
        $this->pathHelper              = $pathHelper;
110
    }
111
112
    /**
113
     * @param string      $className
114
     * @param string      $traitPath
115
     * @param string      $interfacePath
116
     * @param string      $dbalType
117
     * @param null        $defaultValue
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $defaultValue is correct as it would always require null to be passed?
Loading history...
118
     * @param bool        $isUnique
119
     * @param null|string $phpType
120
     *
121
     * @param string      $traitNamespace
122
     * @param string      $interfaceNamespace
123
     *
124
     * @return string
125
     * @throws DoctrineStaticMetaException
126
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
127
     */
128
    public function create(
129
        string $className,
130
        string $traitPath,
131
        string $interfacePath,
132
        string $dbalType,
133
        $defaultValue = null,
134
        bool $isUnique = false,
135
        ?string $phpType = null,
136
        string $traitNamespace,
137
        string $interfaceNamespace
138
    ): string {
139
        $this->traitPath          = $traitPath;
140
        $this->interfacePath      = $interfacePath;
141
        $this->phpType            = $phpType;
142
        $this->defaultValue       = $defaultValue;
143
        $this->isUnique           = $isUnique;
144
        $this->isNullable         = (null === $defaultValue);
145
        $this->dbalType           = $dbalType;
146
        $this->className          = $className;
147
        $this->traitNamespace     = $traitNamespace;
148
        $this->interfaceNamespace = $interfaceNamespace;
149
        $this->generateInterface();
150
151
        return $this->generateTrait();
152
    }
153
154
    /**
155
     * @throws DoctrineStaticMetaException
156
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
157
     */
158
    protected function generateInterface(): void
159
    {
160
        try {
161
            $this->fileSystem->copy(
162
                $this->pathHelper->resolvePath(FieldGenerator::FIELD_INTERFACE_TEMPLATE_PATH),
163
                $this->interfacePath
164
            );
165
            $this->interfacePostCopy($this->interfacePath);
166
            $this->codeHelper->replaceTypeHintsInFile(
167
                $this->interfacePath,
168
                $this->phpType,
0 ignored issues
show
Bug introduced by
It seems like $this->phpType can also be of type null; however, parameter $type of EdmondsCommerce\Doctrine...eplaceTypeHintsInFile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

168
                /** @scrutinizer ignore-type */ $this->phpType,
Loading history...
169
                $this->dbalType,
170
                $this->isNullable
171
            );
172
        } catch (\Exception $e) {
173
            throw new DoctrineStaticMetaException(
174
                'Error in ' . __METHOD__ . ': ' . $e->getMessage(),
175
                $e->getCode(),
176
                $e
177
            );
178
        }
179
    }
180
181
    /**
182
     * @param string $filePath
183
     *
184
     * @throws DoctrineStaticMetaException
185
     */
186
    protected function interfacePostCopy(
187
        string $filePath
188
    ): void {
189
        $this->findAndReplaceHelper->replaceFieldInterfaceNamespace($this->interfaceNamespace, $filePath);
190
        $this->replaceDefaultValueInInterface($filePath);
191
        $this->postCopy($filePath);
192
    }
193
194
    /**
195
     * @param string $filePath
196
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
197
     */
198
    protected function replaceDefaultValueInInterface(
199
        string $filePath
200
    ): void {
201
        $defaultType = $this->typeHelper->getType($this->defaultValue);
202
        switch (true) {
203
            case $defaultType === 'null':
204
                $replace = 'null';
205
                break;
206
            case $this->phpType === 'string':
207
                $replace = "'$this->defaultValue'";
208
                break;
209
            case $this->phpType === 'bool':
210
                $replace = true === $this->defaultValue ? 'true' : 'false';
211
                break;
212
            case $this->phpType === 'float':
213
                $replace = (string)$this->defaultValue;
214
                if (false === \ts\stringContains($replace, '.')) {
215
                    $replace .= '.0';
216
                }
217
                break;
218
            case $this->phpType === 'int':
219
                $replace = (string)$this->defaultValue;
220
                break;
221
            case $this->phpType === 'DateTime':
222
                if ($this->defaultValue !== null) {
223
                    throw new \InvalidArgumentException(
224
                        'Invalid default value ' . $this->defaultValue
225
                        . 'Currently we only support null as a default for DateTime'
226
                    );
227
                }
228
                $replace = 'null';
229
                break;
230
            default:
231
                throw new \RuntimeException(
232
                    'failed to calculate replace based on defaultType ' . $defaultType
233
                    . ' and phpType ' . $this->phpType . ' in ' . __METHOD__
234
                );
235
        }
236
        $this->findAndReplaceHelper->findReplace("'defaultValue'", $replace, $filePath);
237
    }
238
239
    /**
240
     * @param string $filePath
241
     *
242
     * @throws \RuntimeException
243
     * @throws DoctrineStaticMetaException
244
     */
245
    protected function postCopy(
246
        string $filePath
247
    ): void {
248
        $this->fileCreationTransaction::setPathCreated($filePath);
249
        $this->findAndReplaceHelper->replaceName(
250
            $this->codeHelper->classy($this->className),
251
            $filePath,
252
            FieldGenerator::FIND_ENTITY_FIELD_NAME
253
        );
254
        $this->findAndReplaceHelper->findReplace(
255
            $this->codeHelper->consty(FieldGenerator::FIND_ENTITY_FIELD_NAME),
256
            $this->codeHelper->consty($this->className),
257
            $filePath
258
        );
259
        $this->codeHelper->tidyNamespacesInFile($filePath);
260
        $this->setGetterToIsForBools($filePath);
261
    }
262
263
    protected function setGetterToIsForBools(
264
        string $filePath
265
    ): void {
266
        if ($this->phpType !== 'bool') {
267
            return;
268
        }
269
        $replaceName = $this->codeHelper->getGetterMethodNameForBoolean($this->codeHelper->classy($this->className));
270
        $findName    = 'get' . $this->codeHelper->classy($this->className);
271
        $this->findAndReplaceHelper->findReplace($findName, $replaceName, $filePath);
272
    }
273
274
    /**
275
     * @return string
276
     * @throws DoctrineStaticMetaException
277
     * @SuppressWarnings(PHPMD.StaticAccess)
278
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
279
     */
280
    protected function generateTrait(): string
281
    {
282
        try {
283
            $this->fileSystem->copy(
284
                $this->pathHelper->resolvePath(FieldGenerator::FIELD_TRAIT_TEMPLATE_PATH),
285
                $this->traitPath
286
            );
287
            $this->fileCreationTransaction::setPathCreated($this->traitPath);
288
            $this->traitPostCopy($this->traitPath);
289
            $trait = PhpTrait::fromFile($this->traitPath);
290
            $trait->setMethod($this->getPropertyMetaMethod());
291
            $trait->addUseStatement('\\' . MappingHelper::class);
292
            $trait->addUseStatement('\\' . ClassMetadataBuilder::class);
293
            $this->codeHelper->generate($trait, $this->traitPath);
294
            $this->codeHelper->replaceTypeHintsInFile(
295
                $this->traitPath,
296
                $this->phpType,
0 ignored issues
show
Bug introduced by
It seems like $this->phpType can also be of type null; however, parameter $type of EdmondsCommerce\Doctrine...eplaceTypeHintsInFile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

296
                /** @scrutinizer ignore-type */ $this->phpType,
Loading history...
297
                $this->dbalType,
298
                $this->isNullable
299
            );
300
            $this->breakUpdateCallOntoMultipleLines();
301
302
            return $trait->getQualifiedName();
303
        } catch (\Exception $e) {
304
            throw new DoctrineStaticMetaException(
305
                'Error in ' . __METHOD__ . ': ' . $e->getMessage(),
306
                $e->getCode(),
307
                $e
308
            );
309
        }
310
    }
311
312
    /**
313
     * @param string $filePath
314
     *
315
     * @throws \RuntimeException
316
     * @throws DoctrineStaticMetaException
317
     */
318
    protected function traitPostCopy(
319
        string $filePath
320
    ): void {
321
        $this->findAndReplaceHelper->replaceFieldTraitNamespace($this->traitNamespace, $filePath);
322
        $this->findAndReplaceHelper->replaceFieldInterfaceNamespace($this->interfaceNamespace, $filePath);
323
        $this->postCopy($filePath);
324
    }
325
326
    /**
327
     * @return PhpMethod
328
     * @SuppressWarnings(PHPMD.StaticAccess)
329
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
330
     */
331
    protected function getPropertyMetaMethod(): PhpMethod
332
    {
333
        $classy = $this->codeHelper->classy($this->className);
334
        $consty = $this->codeHelper->consty($this->className);
335
        $name   = UsesPHPMetaDataInterface::METHOD_PREFIX_GET_PROPERTY_DOCTRINE_META . $classy;
336
        $method = PhpMethod::create($name);
337
        $method->setStatic(true);
338
        $method->setVisibility('public');
339
        $method->setParameters(
340
            [PhpParameter::create('builder')->setType('ClassMetadataBuilder')]
341
        );
342
        $mappingHelperMethodName = 'setSimple' . ucfirst(strtolower($this->dbalType)) . 'Fields';
343
344
        $methodBody = "
345
        MappingHelper::$mappingHelperMethodName(
346
            [{$classy}FieldInterface::PROP_{$consty}],
347
            \$builder,
348
            {$classy}FieldInterface::DEFAULT_{$consty}
349
        );                        
350
";
351
        if (\in_array($this->dbalType, MappingHelper::UNIQUEABLE_TYPES, true)) {
352
            $isUniqueString = $this->isUnique ? 'true' : 'false';
353
            $methodBody     = "
354
        MappingHelper::$mappingHelperMethodName(
355
            [{$classy}FieldInterface::PROP_{$consty}],
356
            \$builder,
357
            {$classy}FieldInterface::DEFAULT_{$consty},
358
            $isUniqueString
359
        );                        
360
";
361
        }
362
        $method->setBody($methodBody);
363
        $method->setDocblock(
364
            Docblock::create()
365
                    ->appendTag(
366
                        UnknownTag::create('SuppressWarnings(PHPMD.StaticAccess)')
367
                    )
368
        );
369
370
        return $method;
371
    }
372
373
    private function breakUpdateCallOntoMultipleLines(): void
374
    {
375
        $contents = \ts\file_get_contents($this->traitPath);
376
        $indent   = '            ';
377
        $updated  = \preg_replace(
378
            [
379
                '%updatePropertyValue\((.+?),(.+?)\)%',
380
            ],
381
            [
382
                "updatePropertyValue(\n$indent\$1,\n$indent\$2\n        )",
383
            ],
384
            $contents
385
        );
386
        \file_put_contents($this->traitPath, $updated);
387
    }
388
389
    /**
390
     * @return PhpMethod
391
     * @SuppressWarnings(PHPMD.StaticAccess)
392
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
393
     */
394
    protected function getPropertyMetaMethodForDatetime(): PhpMethod
395
    {
396
        $classy = $this->codeHelper->classy($this->className);
397
        $consty = $this->codeHelper->consty($this->className);
398
        $name   = UsesPHPMetaDataInterface::METHOD_PREFIX_GET_PROPERTY_DOCTRINE_META . $classy;
399
        $method = PhpMethod::create($name);
400
        $method->setStatic(true);
401
        $method->setVisibility('public');
402
        $method->setParameters(
403
            [PhpParameter::create('builder')->setType('ClassMetadataBuilder')]
404
        );
405
        $mappingHelperMethodName = 'setSimple' . ucfirst(strtolower($this->dbalType)) . 'Fields';
406
407
        $methodBody = "
408
        MappingHelper::$mappingHelperMethodName(
409
            [{$classy}FieldInterface::PROP_{$consty}],
410
            \$builder,
411
            {$classy}FieldInterface::DEFAULT_{$consty}
412
        );                        
413
";
414
        if (\in_array($this->dbalType, MappingHelper::UNIQUEABLE_TYPES, true)) {
415
            $isUniqueString = $this->isUnique ? 'true' : 'false';
416
            $methodBody     = "
417
        MappingHelper::$mappingHelperMethodName(
418
            [{$classy}FieldInterface::PROP_{$consty}],
419
            \$builder,
420
            {$classy}FieldInterface::DEFAULT_{$consty},
421
            $isUniqueString
422
        );                        
423
";
424
        }
425
        $method->setBody($methodBody);
426
        $method->setDocblock(
427
            Docblock::create()
428
                    ->appendTag(
429
                        UnknownTag::create('SuppressWarnings(PHPMD.StaticAccess)')
430
                    )
431
        );
432
433
        return $method;
434
    }
435
}
436