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.

replaceDefaultValueInInterface()   B
last analyzed

Complexity

Conditions 10
Paths 10

Size

Total Lines 39
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
cc 10
eloc 31
nc 10
nop 1
dl 0
loc 39
ccs 0
cts 39
cp 0
crap 110
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field;
6
7
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
8
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\CodeHelper;
9
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\FileCreationTransaction;
10
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\FindAndReplaceHelper;
11
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\PathHelper;
12
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\TypeHelper;
13
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\UsesPHPMetaDataInterface;
14
use EdmondsCommerce\DoctrineStaticMeta\Entity\Interfaces\ValidatedEntityInterface;
15
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
16
use EdmondsCommerce\DoctrineStaticMeta\MappingHelper;
17
use EdmondsCommerce\DoctrineStaticMeta\Schema\Database;
18
use Exception;
19
use gossi\codegen\model\PhpMethod;
20
use gossi\codegen\model\PhpParameter;
21
use gossi\codegen\model\PhpTrait;
22
use gossi\docblock\Docblock;
23
use gossi\docblock\tags\UnknownTag;
24
use InvalidArgumentException;
25
use RuntimeException;
26
use Symfony\Component\Filesystem\Filesystem;
27
use Symfony\Component\Validator\Constraints\Length;
28
29
use function file_put_contents;
30
use function in_array;
31
use function preg_replace;
32
33
/**
34
 * @deprecated - this is no longer used, will be deleted soon, kept for reasons...
35
 *
36
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
37
 * @SuppressWarnings(PHPMD.TooManyFields)
38
 * @internal   - this is only accessed via CodeGeneration\Generator\Field\FieldGenerator
39
 */
40
class DbalFieldGenerator
41
{
42
    /**
43
     * @var string
44
     */
45
    protected $traitPath;
46
    /**
47
     * @var string
48
     */
49
    protected $interfacePath;
50
    /**
51
     * @var null|string
52
     */
53
    protected $phpType;
54
    /**
55
     * @var null
56
     */
57
    protected $defaultValue;
58
    /**
59
     * @var bool
60
     */
61
    protected $isUnique;
62
    /**
63
     * @var bool
64
     */
65
    protected $isNullable;
66
    /**
67
     * @var string
68
     */
69
    protected $dbalType;
70
    /**
71
     * @var Filesystem
72
     */
73
    protected $fileSystem;
74
    /**
75
     * @var CodeHelper
76
     */
77
    protected $codeHelper;
78
    /**
79
     * @var FileCreationTransaction
80
     */
81
    protected $fileCreationTransaction;
82
    /**
83
     * @var FindAndReplaceHelper
84
     */
85
    protected $findAndReplaceHelper;
86
    /**
87
     * @var string
88
     */
89
    protected $className;
90
    /**
91
     * @var TypeHelper
92
     */
93
    protected $typeHelper;
94
    /**
95
     * @var string
96
     */
97
    protected $traitNamespace;
98
    /**
99
     * @var string
100
     */
101
    protected $interfaceNamespace;
102
    /**
103
     * @var PathHelper
104
     */
105
    protected $pathHelper;
106
107
    public function __construct(
108
        Filesystem $fileSystem,
109
        CodeHelper $codeHelper,
110
        FileCreationTransaction $fileCreationTransaction,
111
        FindAndReplaceHelper $findAndReplaceHelper,
112
        TypeHelper $typeHelper,
113
        PathHelper $pathHelper
114
    ) {
115
        $this->fileSystem              = $fileSystem;
116
        $this->codeHelper              = $codeHelper;
117
        $this->fileCreationTransaction = $fileCreationTransaction;
118
        $this->findAndReplaceHelper    = $findAndReplaceHelper;
119
        $this->typeHelper              = $typeHelper;
120
        $this->pathHelper              = $pathHelper;
121
    }
122
123
    /**
124
     * @param string      $className
125
     * @param string      $traitPath
126
     * @param string      $interfacePath
127
     * @param string      $dbalType
128
     * @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...
129
     * @param bool        $isUnique
130
     * @param null|string $phpType
131
     *
132
     * @param string      $traitNamespace
133
     * @param string      $interfaceNamespace
134
     *
135
     * @return string
136
     * @throws DoctrineStaticMetaException
137
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
138
     */
139
    public function create(
140
        string $className,
141
        string $traitPath,
142
        string $interfacePath,
143
        string $dbalType,
144
        $defaultValue,
145
        bool $isUnique,
146
        ?string $phpType,
147
        string $traitNamespace,
148
        string $interfaceNamespace
149
    ): string {
150
        $this->traitPath          = $traitPath;
151
        $this->interfacePath      = $interfacePath;
152
        $this->phpType            = $phpType;
153
        $this->defaultValue       = $defaultValue;
154
        $this->isUnique           = $isUnique;
155
        $this->isNullable         = (null === $defaultValue);
156
        $this->dbalType           = $dbalType;
157
        $this->className          = $className;
158
        $this->traitNamespace     = $traitNamespace;
159
        $this->interfaceNamespace = $interfaceNamespace;
160
        $this->generateInterface();
161
162
        return $this->generateTrait();
163
    }
164
165
    /**
166
     * @throws DoctrineStaticMetaException
167
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
168
     */
169
    protected function generateInterface(): void
170
    {
171
        try {
172
            $this->fileSystem->copy(
173
                $this->pathHelper->resolvePath(FieldGenerator::FIELD_INTERFACE_TEMPLATE_PATH),
174
                $this->interfacePath
175
            );
176
            $this->interfacePostCopy($this->interfacePath);
177
            $this->codeHelper->replaceTypeHintsInFile(
178
                $this->interfacePath,
179
                $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

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

308
                /** @scrutinizer ignore-type */ $this->phpType,
Loading history...
309
                $this->dbalType,
310
                $this->isNullable
311
            );
312
            $this->breakUpdateCallOntoMultipleLines();
313
314
            return $trait->getQualifiedName();
315
        } catch (Exception $e) {
316
            throw new DoctrineStaticMetaException(
317
                'Error in ' . __METHOD__ . ': ' . $e->getMessage(),
318
                $e->getCode(),
319
                $e
320
            );
321
        }
322
    }
323
324
    /**
325
     * @param string $filePath
326
     *
327
     * @throws RuntimeException
328
     * @throws DoctrineStaticMetaException
329
     */
330
    protected function traitPostCopy(
331
        string $filePath
332
    ): void {
333
        $this->findAndReplaceHelper->replaceFieldTraitNamespace($this->traitNamespace, $filePath);
334
        $this->findAndReplaceHelper->replaceFieldInterfaceNamespace($this->interfaceNamespace, $filePath);
335
        $this->postCopy($filePath);
336
    }
337
338
    /**
339
     * @return PhpMethod
340
     * @SuppressWarnings(PHPMD.StaticAccess)
341
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
342
     */
343
    protected function getPropertyMetaMethod(): PhpMethod
344
    {
345
        $classy = $this->codeHelper->classy($this->className);
346
        $consty = $this->codeHelper->consty($this->className);
347
        $name   = UsesPHPMetaDataInterface::METHOD_PREFIX_GET_PROPERTY_DOCTRINE_META . $classy;
348
        $method = PhpMethod::create($name);
349
        $method->setStatic(true);
350
        $method->setVisibility('public');
351
        $method->setParameters(
352
            [PhpParameter::create('builder')->setType('ClassMetadataBuilder')]
353
        );
354
        $mappingHelperMethodName = 'setSimple' . ucfirst(strtolower($this->phpType)) . 'Fields';
355
356
        $methodBody = "
357
        MappingHelper::$mappingHelperMethodName(
358
            [{$classy}FieldInterface::PROP_{$consty}],
359
            \$builder,
360
            {$classy}FieldInterface::DEFAULT_{$consty}
361
        );                        
362
";
363
        if (in_array($this->dbalType, MappingHelper::UNIQUEABLE_TYPES, true)) {
364
            $isUniqueString = $this->isUnique ? 'true' : 'false';
365
            $methodBody     = "
366
        MappingHelper::$mappingHelperMethodName(
367
            [{$classy}FieldInterface::PROP_{$consty}],
368
            \$builder,
369
            {$classy}FieldInterface::DEFAULT_{$consty},
370
            $isUniqueString
371
        );                        
372
";
373
        }
374
        $method->setBody($methodBody);
375
        $method->setDocblock(
376
            Docblock::create()
377
                    ->appendTag(
378
                        UnknownTag::create('SuppressWarnings(PHPMD.StaticAccess)')
379
                    )
380
        );
381
382
        return $method;
383
    }
384
385
    private function setStringLengthValidation(PhpTrait $trait): void
386
    {
387
        if ($this->dbalType !== MappingHelper::TYPE_STRING) {
388
            return;
389
        }
390
391
392
        $classy = $this->codeHelper->classy($this->className);
393
        $consty = $this->codeHelper->consty($this->className);
394
        $name   = ValidatedEntityInterface::METHOD_PREFIX_PROPERTY_VALIDATOR_META . $classy;
395
        $method = $trait->getMethod($name);
396
397
        $methodBody = <<<PHP
398
        \$metadata->addPropertyConstraint(
399
            {$classy}FieldInterface::PROP_{$consty},
400
            new Length(['min' => 0, 'max' => Database::MAX_VARCHAR_LENGTH])
401
        );
402
PHP;
403
        $method->setBody($methodBody);
404
        $trait->addUseStatement(Length::class);
405
        $trait->addUseStatement(Database::class);
406
    }
407
408
    private function breakUpdateCallOntoMultipleLines(): void
409
    {
410
        $contents = \ts\file_get_contents($this->traitPath);
411
        $indent   = '            ';
412
        $updated  = preg_replace(
413
            [
414
                '%updatePropertyValue\((.+?),(.+?)\)%',
415
            ],
416
            [
417
                "updatePropertyValue(\n$indent\$1,\n$indent\$2\n        )",
418
            ],
419
            $contents
420
        );
421
        file_put_contents($this->traitPath, $updated);
422
    }
423
424
    /**
425
     * @return PhpMethod
426
     * @SuppressWarnings(PHPMD.StaticAccess)
427
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
428
     */
429
    protected function getPropertyMetaMethodForDatetime(): PhpMethod
430
    {
431
        $classy = $this->codeHelper->classy($this->className);
432
        $consty = $this->codeHelper->consty($this->className);
433
        $name   = UsesPHPMetaDataInterface::METHOD_PREFIX_GET_PROPERTY_DOCTRINE_META . $classy;
434
        $method = PhpMethod::create($name);
435
        $method->setStatic(true);
436
        $method->setVisibility('public');
437
        $method->setParameters(
438
            [PhpParameter::create('builder')->setType('ClassMetadataBuilder')]
439
        );
440
        $mappingHelperMethodName = 'setSimple' . ucfirst(strtolower($this->dbalType)) . 'Fields';
441
442
        $methodBody = "
443
        MappingHelper::$mappingHelperMethodName(
444
            [{$classy}FieldInterface::PROP_{$consty}],
445
            \$builder,
446
            {$classy}FieldInterface::DEFAULT_{$consty}
447
        );                        
448
";
449
        if (in_array($this->dbalType, MappingHelper::UNIQUEABLE_TYPES, true)) {
450
            $isUniqueString = $this->isUnique ? 'true' : 'false';
451
            $methodBody     = "
452
        MappingHelper::$mappingHelperMethodName(
453
            [{$classy}FieldInterface::PROP_{$consty}],
454
            \$builder,
455
            {$classy}FieldInterface::DEFAULT_{$consty},
456
            $isUniqueString
457
        );                        
458
";
459
        }
460
        $method->setBody($methodBody);
461
        $method->setDocblock(
462
            Docblock::create()
463
                    ->appendTag(
464
                        UnknownTag::create('SuppressWarnings(PHPMD.StaticAccess)')
465
                    )
466
        );
467
468
        return $method;
469
    }
470
}
471