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

FieldGenerator::assertFileDoesNotExist()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
cc 2
nc 2
nop 2
crap 2
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\Field;
4
5
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\CodeHelper;
6
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\AbstractGenerator;
7
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\FileCreationTransaction;
8
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\FindAndReplaceHelper;
9
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
10
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\PathHelper;
11
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\TypeHelper;
12
use EdmondsCommerce\DoctrineStaticMeta\Config;
13
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\Boolean\ApprovedFieldTrait;
0 ignored issues
show
Bug introduced by
The type EdmondsCommerce\Doctrine...lean\ApprovedFieldTrait was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\Boolean\DefaultFieldTrait;
0 ignored issues
show
Bug introduced by
The type EdmondsCommerce\Doctrine...olean\DefaultFieldTrait was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\Boolean\DefaultsDisabledFieldTrait;
16
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\Boolean\DefaultsEnabledFieldTrait;
17
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\Boolean\DefaultsNullFieldTrait;
18
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\DateTime\DateTimeSettableNoDefaultFieldTrait;
19
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\DateTime\DateTimeSettableOnceFieldTrait;
20
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\BusinessIdentifierCodeFieldTrait;
21
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\CountryCodeFieldTrait;
22
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\EmailAddressFieldTrait;
23
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\IpAddressFieldTrait;
24
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\IsbnFieldTrait;
25
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\LocaleIdentifierFieldTrait;
26
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\NullableStringFieldTrait;
27
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\SettableUuidFieldTrait;
28
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\UnicodeLanguageIdentifierFieldTrait;
29
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\UniqueStringFieldTrait;
30
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\String\UrlFieldTrait;
31
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\TimeStamp\ActionedDateFieldTrait;
0 ignored issues
show
Bug introduced by
The type EdmondsCommerce\Doctrine...\ActionedDateFieldTrait was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
32
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\TimeStamp\ActivatedDateFieldTrait;
0 ignored issues
show
Bug introduced by
The type EdmondsCommerce\Doctrine...ActivatedDateFieldTrait was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
33
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\TimeStamp\CompletedDateFieldTrait;
0 ignored issues
show
Bug introduced by
The type EdmondsCommerce\Doctrine...CompletedDateFieldTrait was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\TimeStamp\CreationTimestampFieldTrait;
35
use EdmondsCommerce\DoctrineStaticMeta\Entity\Fields\Traits\TimeStamp\DeactivatedDateFieldTrait;
0 ignored issues
show
Bug introduced by
The type EdmondsCommerce\Doctrine...activatedDateFieldTrait was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
36
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
37
use EdmondsCommerce\DoctrineStaticMeta\MappingHelper;
38
use Symfony\Component\Filesystem\Filesystem;
39
40
/**
41
 * Class FieldGenerator
42
 *
43
 * @package EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator
44
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
45
 */
46
class FieldGenerator extends AbstractGenerator
47
{
48
    public const FIELD_TRAIT_SUFFIX = 'FieldTrait';
49
50
    /**
51
     * @var string
52
     */
53
    protected $fieldsPath;
54
55
    /**
56
     * @var string
57
     */
58
    protected $fieldsInterfacePath;
59
60
    /**
61
     * @var string
62
     */
63
    protected $phpType;
64
65
    /**
66
     * @var string
67
     */
68
    protected $fieldType;
69
70
    /**
71
     * Are we currently generating an archetype based field?
72
     *
73
     * @var bool
74
     */
75
    protected $isArchetype = false;
76
77
    /**
78
     * @var bool
79
     */
80
    protected $isNullable;
81
82
    /**
83
     * @var bool
84
     */
85
    protected $isUnique;
86
87
    /**
88
     * @var mixed
89
     */
90
    protected $defaultValue;
91
92
    /**
93
     * @var string
94
     */
95
    protected $traitNamespace;
96
97
    /**
98
     * @var string
99
     */
100
    protected $interfaceNamespace;
101
102
    public const STANDARD_FIELDS = [
103
        DefaultsDisabledFieldTrait::class,
104
        DefaultsEnabledFieldTrait::class,
105
        DefaultsNullFieldTrait::class,
106
        DateTimeSettableNoDefaultFieldTrait::class,
107
        DateTimeSettableOnceFieldTrait::class,
108
        BusinessIdentifierCodeFieldTrait::class,
109
        CountryCodeFieldTrait::class,
110
        EmailAddressFieldTrait::class,
111
        IpAddressFieldTrait::class,
112
        IsbnFieldTrait::class,
113
        LocaleIdentifierFieldTrait::class,
114
        NullableStringFieldTrait::class,
115
        SettableUuidFieldTrait::class,
116
        UnicodeLanguageIdentifierFieldTrait::class,
117
        UniqueStringFieldTrait::class,
118
        UrlFieldTrait::class,
119
        CreationTimestampFieldTrait::class,
120
    ];
121
122
    /**
123
     * @var TypeHelper
124
     */
125
    protected $typeHelper;
126
    /**
127
     * @var ArchetypeFieldGenerator
128
     */
129
    protected $archetypeFieldCopier;
130
    /**
131
     * @var string
132
     */
133
    protected $fieldFqn;
134
    /**
135
     * @var string
136
     */
137
    protected $className;
138
139
140 33
    public function __construct(
141
        Filesystem $filesystem,
142
        FileCreationTransaction $fileCreationTransaction,
143
        NamespaceHelper $namespaceHelper,
144
        Config $config,
145
        CodeHelper $codeHelper,
146
        PathHelper $pathHelper,
147
        FindAndReplaceHelper $findAndReplaceHelper,
148
        TypeHelper $typeHelper
149
    ) {
150 33
        parent::__construct(
151 33
            $filesystem,
152 33
            $fileCreationTransaction,
153 33
            $namespaceHelper,
154 33
            $config,
155 33
            $codeHelper,
156 33
            $pathHelper,
157 33
            $findAndReplaceHelper
158
        );
159 33
        $this->typeHelper = $typeHelper;
160 33
    }
161
162
163
    /**
164
     * Generate a new Field based on a property name and Doctrine Type or Archetype field FQN
165
     *
166
     * @see MappingHelper::ALL_DBAL_TYPES for the full list of Dbal Types
167
     *
168
     * @param string      $fieldFqn
169
     * @param string      $fieldType
170
     * @param null|string $phpType
171
     *
172
     * @param mixed       $defaultValue
173
     * @param bool        $isUnique
174
     *
175
     * @return string - The Fully Qualified Name of the generated Field Trait
176
     *
177
     * @throws DoctrineStaticMetaException
178
     * @throws \ReflectionException
179
     * @SuppressWarnings(PHPMD.StaticAccess)
180
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
181
     */
182 32
    public function generateField(
183
        string $fieldFqn,
184
        string $fieldType,
185
        ?string $phpType = null,
186
        $defaultValue = null,
187
        bool $isUnique = false
188
    ): string {
189 32
        $this->validateArguments($fieldFqn, $fieldType, $phpType);
190 28
        $this->setupClassProperties($fieldFqn, $fieldType, $phpType, $defaultValue, $isUnique);
191
192 28
        $this->pathHelper->ensurePathExists($this->fieldsPath);
193 28
        $this->pathHelper->ensurePathExists($this->fieldsInterfacePath);
194
195 28
        $this->assertFileDoesNotExist($this->getTraitPath(), 'Trait');
196 28
        $this->assertFileDoesNotExist($this->getInterfacePath(), 'Interface');
197
198 28
        if (true === $this->isArchetype) {
199 2
            return $this->createFieldFromArchetype();
200
        }
201
202 27
        return $this->createDbalField();
203
    }
204
205 28
    protected function getTraitPath(): string
206
    {
207 28
        return $this->fieldsPath.'/'.$this->codeHelper->classy($this->className).'FieldTrait.php';
208
    }
209
210
211 28
    protected function getInterfacePath(): string
212
    {
213 28
        return $this->fieldsInterfacePath.'/'.$this->codeHelper->classy($this->className).'FieldInterface.php';
214
    }
215
216
    /**
217
     * @return string
218
     * @throws DoctrineStaticMetaException
219
     */
220 27
    protected function createDbalField(): string
221
    {
222 27
        $creator = new DbalFieldGenerator(
223 27
            $this->fileSystem,
224 27
            $this->codeHelper,
225 27
            $this->fileCreationTransaction,
226 27
            $this->findAndReplaceHelper,
227 27
            $this->typeHelper,
228 27
            $this->pathHelper
229
        );
230
231 27
        return $creator->create(
232 27
            $this->className,
233 27
            $this->getTraitPath(),
234 27
            $this->getInterfacePath(),
235 27
            $this->fieldType,
236 27
            $this->defaultValue,
237 27
            $this->isUnique,
238 27
            $this->phpType,
239 27
            $this->traitNamespace,
240 27
            $this->interfaceNamespace
241
        );
242
    }
243
244
    /**
245
     * @return string
246
     * @throws \ReflectionException
247
     */
248 2
    protected function createFieldFromArchetype(): string
249
    {
250 2
        $copier = new ArchetypeFieldGenerator(
251 2
            $this->fileSystem,
252 2
            $this->namespaceHelper,
253 2
            $this->codeHelper,
254 2
            $this->findAndReplaceHelper
255
        );
256
257 2
        return $copier->createFromArchetype(
258 2
            $this->fieldFqn,
259 2
            $this->getTraitPath(),
260 2
            $this->getInterfacePath(),
261 2
            '\\'.$this->fieldType,
262 2
            $this->projectRootNamespace
263 2
        ).self::FIELD_TRAIT_SUFFIX;
264
    }
265
266 32
    protected function validateArguments(
267
        string $fieldFqn,
268
        string $fieldType,
269
        ?string $phpType
270
    ): void {
271
        //Check for a correct looking field FQN
272 32
        if (false === \strpos($fieldFqn, AbstractGenerator::ENTITY_FIELD_TRAIT_NAMESPACE)) {
273 1
            throw new \InvalidArgumentException(
274 1
                'Fully qualified name [ '.$fieldFqn.' ]'
275 1
                .' does not include [ '.AbstractGenerator::ENTITY_FIELD_TRAIT_NAMESPACE.' ].'."\n"
276 1
                .'Please ensure you pass in the full namespace qualified field name'
277
            );
278
        }
279
        //Check that the field type is either a Dbal Type or a Field Archetype FQN
280 31
        if (false === \in_array(\strtolower($fieldType), MappingHelper::ALL_DBAL_TYPES, true)
281 31
            && false === \in_array($fieldType, self::STANDARD_FIELDS, true)
282 31
            && false === $this->traitFqnLooksLikeField($fieldType)
283
        ) {
284
            throw new \InvalidArgumentException(
285
                'fieldType '.$fieldType.' is not a valid field type'
286
            );
287
        }
288
        //Check the phpType is valid
289 30
        if ((null !== $phpType)
290 30
            && (false === \in_array($phpType, MappingHelper::PHP_TYPES, true))
291
        ) {
292 2
            throw new \InvalidArgumentException(
293 2
                'phpType must be either null or one of MappingHelper::PHP_TYPES'
294
            );
295
        }
296 28
    }
297
298
    /**
299
     * Does the specified trait FQN look like a field trait?
300
     *
301
     * @param string $traitFqn
302
     *
303
     * @return bool
304
     * @throws \ReflectionException
305
     */
306 2
    protected function traitFqnLooksLikeField(string $traitFqn): bool
307
    {
308
        try {
309 2
            $reflection = new \ReflectionClass($traitFqn);
310 1
        } catch (\ReflectionException $e) {
311 1
            throw new \InvalidArgumentException(
312 1
                'invalid traitFqn '.$traitFqn.' does not seem to exist',
313 1
                $e->getCode(),
314 1
                $e
315
            );
316
        }
317 1
        if (true !== $reflection->isTrait()) {
318
            throw new \InvalidArgumentException('field type is not a trait FQN');
319
        }
320 1
        if ('FieldTrait' !== \substr($traitFqn, -\strlen('FieldTrait'))) {
321
            throw new \InvalidArgumentException('traitFqn does not end in FieldTrait');
322
        }
323
324 1
        return true;
325
    }
326
327
    /**
328
     * Defining the properties for the field to be generated
329
     *
330
     * @param string      $fieldFqn
331
     * @param string      $fieldType
332
     * @param null|string $phpType
333
     * @param mixed       $defaultValue
334
     * @param bool        $isUnique
335
     *
336
     * @throws DoctrineStaticMetaException
337
     * @SuppressWarnings(PHPMD.StaticAccess)
338
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
339
     */
340 28
    protected function setupClassProperties(
341
        string $fieldFqn,
342
        string $fieldType,
343
        ?string $phpType,
344
        $defaultValue,
345
        bool $isUnique
346
    ): void {
347 28
        $this->fieldType = \strtolower($fieldType);
348 28
        if (true !== \in_array($this->fieldType, MappingHelper::COMMON_TYPES, true)) {
349 2
            $this->isArchetype = true;
350 2
            $this->fieldType   = $fieldType;
351
        }
352 28
        $this->phpType      = $phpType ?? $this->getPhpTypeForDbalType();
353 28
        $this->defaultValue = $this->typeHelper->normaliseValueToType($defaultValue, $this->phpType);
354
355 28
        if (null !== $this->defaultValue) {
356 1
            $defaultValueType = $this->typeHelper->getType($this->defaultValue);
357 1
            if ($defaultValueType !== $this->phpType) {
358
                throw new \InvalidArgumentException(
359
                    'default value '.$this->defaultValue.' has the type: '.$defaultValueType
360
                    .' whereas the phpType for this field has been set as '.$this->phpType.', these do not match up'
361
                );
362
            }
363
        }
364 28
        $this->isNullable = (null === $defaultValue);
365 28
        $this->isUnique   = $isUnique;
366
367 28
        if (\substr($fieldFqn, -\strlen(self::FIELD_TRAIT_SUFFIX)) === self::FIELD_TRAIT_SUFFIX) {
368 4
            $fieldFqn = \substr($fieldFqn, 0, -\strlen(self::FIELD_TRAIT_SUFFIX));
369
        }
370 28
        $this->fieldFqn = $fieldFqn;
371
372 28
        list($className, $traitNamespace, $traitSubDirectories) = $this->parseFullyQualifiedName(
373 28
            $fieldFqn,
374 28
            $this->srcSubFolderName
375
        );
376 28
        $this->className = $className;
377 28
        list(, $interfaceNamespace, $interfaceSubDirectories) = $this->parseFullyQualifiedName(
378 28
            \str_replace('Traits', 'Interfaces', $fieldFqn),
379 28
            $this->srcSubFolderName
380
        );
381
382 28
        $this->fieldsPath = $this->pathHelper->resolvePath(
383 28
            $this->pathToProjectRoot.'/'.\implode('/', $traitSubDirectories)
384
        );
385
386 28
        $this->fieldsInterfacePath = $this->pathHelper->resolvePath(
387 28
            $this->pathToProjectRoot.'/'.\implode('/', $interfaceSubDirectories)
388
        );
389
390 28
        $this->traitNamespace     = $traitNamespace;
391 28
        $this->interfaceNamespace = $interfaceNamespace;
392 28
    }
393
394 28
    private function assertFileDoesNotExist(string $filePath, string $type): void
395
    {
396 28
        if (file_exists($filePath)) {
397 1
            throw new \RuntimeException("Field $type already exists at $filePath");
398
        }
399 28
    }
400
401
    /**
402
     * @return string
403
     * @throws DoctrineStaticMetaException
404
     *
405
     */
406 28
    protected function getPhpTypeForDbalType(): string
407
    {
408 28
        if (true === $this->isArchetype) {
409 2
            return '';
410
        }
411 27
        if (!\in_array($this->fieldType, MappingHelper::COMMON_TYPES, true)) {
412
            throw new DoctrineStaticMetaException(
413
                'Field type of '.$this->fieldType.' is not one of MappingHelper::COMMON_TYPES'
414
                ."\n\nYou can only use this fieldType type if you pass in the explicit phpType as well "
415
                ."\n\nAlternatively, suggest you set the type as string and then edit the generated code as you see fit"
416
            );
417
        }
418
419 27
        return MappingHelper::COMMON_TYPES_TO_PHP_TYPES[$this->fieldType];
420
    }
421
}
422