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 (#214)
by joseph
16:19
created

MappingHelper::setSimpleDatetimeFields()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 12
dl 0
loc 21
rs 9.8666
c 0
b 0
f 0
ccs 12
cts 12
cp 1
cc 3
nc 3
nop 3
crap 3
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta;
4
5
use DateTimeImmutable;
6
use Doctrine\Common\Inflector\Inflector;
7
use Doctrine\DBAL\Types\Type;
8
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
9
use Doctrine\ORM\Mapping\Builder\FieldBuilder;
10
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
11
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\TypeHelper;
12
use EdmondsCommerce\DoctrineStaticMeta\Schema\Database;
13
use InvalidArgumentException;
14
use Ramsey\Uuid\Doctrine\UuidBinaryOrderedTimeType;
15
use Ramsey\Uuid\Doctrine\UuidBinaryType;
16
use Ramsey\Uuid\Doctrine\UuidType;
17
use function is_bool;
18
use function is_float;
19
use function is_int;
20
use function is_string;
21
use function str_replace;
22
use function strlen;
23
24
/**
25
 * Class MappingHelper
26
 *
27
 * Helper functions to assist with setting up Doctrine mapping meta data
28
 *
29
 * @package EdmondsCommerce\DoctrineStaticMeta
30
 *
31
 * @SuppressWarnings(PHPMD.StaticAccess)
32
 */
33
class MappingHelper
34
{
35
36
    /**
37
     * Primary Key types (beyond the common types)
38
     */
39
    public const TYPE_UUID                    = UuidBinaryOrderedTimeType::NAME;
40
    public const TYPE_NON_BINARY_UUID         = UuidType::NAME;
41
    public const TYPE_NON_ORDERED_BINARY_UUID = UuidBinaryType::NAME;
42
43
    /**
44
     * Quick accessors for common types that are supported by methods in this helper
45
     *
46
     * Note this is not all of the types supported by Doctrine
47
     *
48
     * Each of these methods has a corresponding `setSimple{Type}Fields` method
49
     */
50
    public const TYPE_STRING   = 'string';
51
    public const TYPE_DATETIME = 'datetime';// actually datetime is implemented as datetime_immutable
52
    public const TYPE_FLOAT    = 'float';
53
    public const TYPE_DECIMAL  = 'decimal';
54
    public const TYPE_INTEGER  = 'integer';
55
    public const TYPE_TEXT     = 'text';
56
    public const TYPE_BOOLEAN  = 'boolean';
57
    public const TYPE_ARRAY    = 'array';
58
    public const TYPE_OBJECT   = 'object';
59
60
61
    /**
62
     * This is the list of common types that mapping helper fully supports with a `setSimple{Type}Fields` method
63
     */
64
    public const COMMON_TYPES = [
65
        self::TYPE_STRING,
66
        self::TYPE_DATETIME,
67
        self::TYPE_FLOAT,
68
        self::TYPE_DECIMAL,
69
        self::TYPE_INTEGER,
70
        self::TYPE_TEXT,
71
        self::TYPE_BOOLEAN,
72
        self::TYPE_ARRAY,
73
        self::TYPE_OBJECT,
74
    ];
75
76
    /**
77
     * Which types do we support marking as unique
78
     */
79
    public const UNIQUEABLE_TYPES = [
80
        self::TYPE_STRING,
81
        self::TYPE_INTEGER,
82
    ];
83
84
    public const PHP_TYPE_STRING   = 'string';
85
    public const PHP_TYPE_DATETIME = '\\' . DateTimeImmutable::class;
86
    public const PHP_TYPE_FLOAT    = 'float';
87
    public const PHP_TYPE_INTEGER  = 'int';
88
    public const PHP_TYPE_BOOLEAN  = 'bool';
89
    public const PHP_TYPE_ARRAY    = 'array';
90
    public const PHP_TYPE_OBJECT   = 'object';
91
92
    public const PHP_TYPES = [
93
        self::PHP_TYPE_STRING,
94
        self::PHP_TYPE_DATETIME,
95
        self::PHP_TYPE_FLOAT,
96
        self::PHP_TYPE_INTEGER,
97
        self::PHP_TYPE_BOOLEAN,
98
        self::PHP_TYPE_ARRAY,
99
        self::PHP_TYPE_OBJECT,
100
    ];
101
102
    /**
103
     * The PHP type associated with the mapping type
104
     */
105
    public const COMMON_TYPES_TO_PHP_TYPES = [
106
        self::TYPE_STRING   => self::PHP_TYPE_STRING,
107
        self::TYPE_DATETIME => self::PHP_TYPE_DATETIME,
108
        self::TYPE_FLOAT    => self::PHP_TYPE_FLOAT,
109
        self::TYPE_DECIMAL  => self::PHP_TYPE_STRING,
110
        self::TYPE_INTEGER  => self::PHP_TYPE_INTEGER,
111
        self::TYPE_TEXT     => self::PHP_TYPE_STRING,
112
        self::TYPE_BOOLEAN  => self::PHP_TYPE_BOOLEAN,
113
        self::TYPE_ARRAY    => self::PHP_TYPE_ARRAY,
114
        self::TYPE_OBJECT   => self::PHP_TYPE_OBJECT,
115
    ];
116
117
    /**
118
     * This is the full list of mapping types
119
     *
120
     * @see \Doctrine\DBAL\Types\Type
121
     */
122
    public const ALL_DBAL_TYPES = [
123
        Type::TARRAY,
124
        Type::SIMPLE_ARRAY,
125
        Type::JSON,
126
        Type::JSON_ARRAY,
127
        Type::BIGINT,
128
        Type::BOOLEAN,
129
        Type::DATETIME,
130
        Type::DATETIME_IMMUTABLE,
131
        Type::DATETIMETZ,
132
        Type::DATETIMETZ_IMMUTABLE,
133
        Type::DATE,
134
        Type::DATE_IMMUTABLE,
135
        Type::TIME,
136
        Type::TIME_IMMUTABLE,
137
        Type::DECIMAL,
138
        Type::INTEGER,
139
        Type::OBJECT,
140
        Type::SMALLINT,
141
        Type::STRING,
142
        Type::TEXT,
143
        Type::BINARY,
144
        Type::BLOB,
145
        Type::FLOAT,
146
        Type::GUID,
147
        Type::DATEINTERVAL,
148
    ];
149
150
    public const MIXED_TYPES = [
151
        // Doctrine hydrates decimal values as strings.
152
        // However, setting these using an int or float is also valid.
153
        self::TYPE_DECIMAL,
154
    ];
155
156
    /**
157
     * @param string $entityFqn
158
     *
159
     * @return string
160
     */
161 2
    public static function getPluralForFqn(string $entityFqn): string
162
    {
163 2
        $singular = self::getSingularForFqn($entityFqn);
164
165 2
        $plural = self::pluralize($singular);
166 2
        if ($plural === $singular) {
167
            $plural = $singular . 's';
168
        }
169
170 2
        return $plural;
171
    }
172
173
    /**
174
     * @param string $entityFqn
175
     *
176
     * @return string
177
     */
178 21
    public static function getSingularForFqn(string $entityFqn): string
179
    {
180 21
        $shortName = self::getShortNameForFqn($entityFqn);
181 21
        $singular  = self::singularize($shortName);
182
183 21
        return lcfirst($singular);
184
    }
185
186
    /**
187
     * @param string $entityFqn
188
     *
189
     * @return string
190
     */
191 21
    public static function getShortNameForFqn(string $entityFqn): string
192
    {
193 21
        return substr($entityFqn, strrpos($entityFqn, '\\') + 1);
194
    }
195
196 21
    public static function singularize(string $item): string
197
    {
198 21
        $singular = Inflector::singularize($item);
199 21
        if ('datum' === strtolower(substr($singular, -5))) {
200 2
            $singular = $item;
201
        }
202
203 21
        return $singular;
204
    }
205
206 2
    public static function pluralize(string $item): string
207
    {
208 2
        $plural = Inflector::pluralize($item);
209 2
        if ($plural === $item) {
210 2
            $plural = $item . 's';
211
        }
212
213 2
        return $plural;
214
    }
215
216
    /**
217
     * @param string $entityFqn
218
     *
219
     * @return string
220
     */
221 4
    public static function getTableNameForEntityFqn(
222
        string $entityFqn
223
    ): string {
224 4
        $namespaceHelper = new NamespaceHelper();
225 4
        $subFqn          = $namespaceHelper->getEntitySubNamespace(
226 4
            $entityFqn
227
        );
228 4
        $tableName       = str_replace('\\', '', $subFqn);
229 4
        $tableName       = self::backticks(Inflector::tableize($tableName));
230 4
        if (strlen($tableName) > Database::MAX_IDENTIFIER_LENGTH) {
231
            $tableName = substr($tableName, -Database::MAX_IDENTIFIER_LENGTH);
232
        }
233
234 4
        return $tableName;
235
    }
236
237
    /**
238
     * Wrap the name in backticks
239
     *
240
     * @param string $name
241
     *
242
     * @return string
243
     */
244 6
    public static function backticks(string $name): string
245
    {
246 6
        return '`' . $name . '`';
247
    }
248
249
    /**
250
     * Set bog standard string fields quickly in bulk
251
     *
252
     * @param array                $fields
253
     * @param ClassMetadataBuilder $builder
254
     * @param mixed                $default
255
     * @param bool                 $isUnique
256
     * In this case the boolean argument is simply data
257
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
258
     */
259 3
    public static function setSimpleStringFields(
260
        array $fields,
261
        ClassMetadataBuilder $builder,
262
        $default = null,
263
        bool $isUnique = false
264
    ): void {
265 3
        if (null !== $default && !is_string($default)) {
266 1
            throw new InvalidArgumentException(
267 1
                'Invalid default value ' . $default
268 1
                . ' with type ' . self::getType($default)
269
            );
270
        }
271 2
        foreach ($fields as $field) {
272 2
            $fieldBuilder = new FieldBuilder(
273 2
                $builder,
274
                [
275 2
                    'fieldName' => $field,
276 2
                    'type'      => Type::STRING,
277 2
                    'default'   => $default,
278
                ]
279
            );
280
            $fieldBuilder
281 2
                ->columnName(self::getColumnNameForField($field))
282 2
                ->nullable(null === $default)
283 2
                ->unique($isUnique)
284 2
                ->length(Database::MAX_VARCHAR_LENGTH)
285 2
                ->build();
286
        }
287 2
    }
288
289 5
    private static function getType($var): string
290
    {
291 5
        static $typeHelper;
292 5
        if (null === $typeHelper) {
293 1
            $typeHelper = new TypeHelper();
294
        }
295
296 5
        return $typeHelper->getType($var);
297
    }
298
299
    /**
300
     * Get the properly backticked and formatted column name for a field
301
     *
302
     * @param string $field
303
     *
304
     * @return string
305
     */
306 4
    public static function getColumnNameForField(string $field): string
307
    {
308 4
        return self::backticks(Inflector::tableize($field));
309
    }
310
311
    /**
312
     * Set bog standard text fields quickly in bulk
313
     *
314
     * @param array                $fields
315
     * @param ClassMetadataBuilder $builder
316
     * @param mixed                $default
317
     * In this case the boolean argument is simply data
318
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
319
     */
320 3
    public static function setSimpleTextFields(
321
        array $fields,
322
        ClassMetadataBuilder $builder,
323
        $default = null
324
    ): void {
325 3
        if (null !== $default && !is_string($default)) {
326 1
            throw new InvalidArgumentException(
327 1
                'Invalid default value ' . $default
328 1
                . ' with type ' . self::getType($default)
329
            );
330
        }
331 2
        foreach ($fields as $field) {
332 2
            $fieldBuilder = new FieldBuilder(
333 2
                $builder,
334
                [
335 2
                    'fieldName' => $field,
336 2
                    'type'      => Type::TEXT,
337 2
                    'default'   => $default,
338
                ]
339
            );
340 2
            $fieldBuilder->columnName(self::getColumnNameForField($field))
341 2
                         ->nullable(null === $default)
342 2
                         ->build();
343
        }
344 2
    }
345
346
347
    /**
348
     * Set bog standard float fields quickly in bulk
349
     *
350
     * @param array                $fields
351
     * @param ClassMetadataBuilder $builder
352
     * @param mixed                $default
353
     * In this case the boolean argument is simply data
354
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
355
     */
356 3
    public static function setSimpleFloatFields(
357
        array $fields,
358
        ClassMetadataBuilder $builder,
359
        $default = null
360
    ): void {
361 3
        if (null !== $default && !is_float($default)) {
362 1
            throw new InvalidArgumentException(
363 1
                'Invalid default value ' . $default
364 1
                . ' with type ' . self::getType($default)
365
            );
366
        }
367 2
        foreach ($fields as $field) {
368 2
            $fieldBuilder = new FieldBuilder(
369 2
                $builder,
370
                [
371 2
                    'fieldName' => $field,
372 2
                    'type'      => Type::FLOAT,
373 2
                    'default'   => $default,
374
                ]
375
            );
376
            $fieldBuilder
377 2
                ->columnName(self::getColumnNameForField($field))
378 2
                ->nullable(null === $default)
379 2
                ->build();
380
        }
381 2
    }
382
383
    /**
384
     * Set bog standard decimal fields quickly in bulk
385
     *
386
     * @param array                $fields
387
     * @param ClassMetadataBuilder $builder
388
     * @param mixed                $default
389
     * In this case the boolean argument is simply data
390
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
391
     */
392 3
    public static function setSimpleDecimalFields(
393
        array $fields,
394
        ClassMetadataBuilder $builder,
395
        $default = null
396
    ): void {
397 3
        if (null !== $default && !is_string($default)) {
398
            throw new InvalidArgumentException(
399
                'Invalid default value ' . $default
400
                . ' with type ' . self::getType($default)
401
            );
402
        }
403 3
        if (null !== $default && !is_numeric($default)) {
404 1
            throw new InvalidArgumentException(
405 1
                'Invalid default value ' . $default
406 1
                . ', even though it is a string, it must be numeric '
407
            );
408
        }
409 2
        foreach ($fields as $field) {
410 2
            $fieldBuilder = new FieldBuilder(
411 2
                $builder,
412
                [
413 2
                    'fieldName' => $field,
414 2
                    'type'      => Type::DECIMAL,
415 2
                    'default'   => (string)(float)$default,
416
                ]
417
            );
418
            $fieldBuilder
419 2
                ->columnName(self::getColumnNameForField($field))
420 2
                ->nullable(null === $default)
421 2
                ->precision(Database::MAX_DECIMAL_PRECISION)
422 2
                ->scale(Database::MAX_DECIMAL_SCALE)
423 2
                ->build();
424
        }
425 2
    }
426
427
    /**
428
     * Set bog standard dateTime fields quickly in bulk
429
     *
430
     * @param array                $fields
431
     * @param ClassMetadataBuilder $builder
432
     * @param mixed                $default
433
     * In this case the boolean argument is simply data
434
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
435
     */
436 3
    public static function setSimpleDatetimeFields(
437
        array $fields,
438
        ClassMetadataBuilder $builder,
439
        $default = null
440
    ): void {
441 3
        if (null !== $default) {
442 1
            throw new InvalidArgumentException('DateTime currently only support null as a default value');
443
        }
444 2
        foreach ($fields as $field) {
445 2
            $fieldBuilder = new FieldBuilder(
446 2
                $builder,
447
                [
448 2
                    'fieldName' => $field,
449 2
                    'type'      => Type::DATETIME_IMMUTABLE,
450 2
                    'default'   => $default,
451
                ]
452
            );
453
            $fieldBuilder
454 2
                ->columnName(self::getColumnNameForField($field))
455 2
                ->nullable(null === $default)
456 2
                ->build();
457
        }
458 2
    }
459
460
    /**
461
     * @param array                $fields
462
     * @param ClassMetadataBuilder $builder
463
     * @param null                 $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
464
     * @param bool                 $isUnique
465
     */
466 3
    public static function setSimpleIntegerFields(
467
        array $fields,
468
        ClassMetadataBuilder $builder,
469
        $default = null,
470
        bool $isUnique = false
471
    ): void {
472 3
        if (null !== $default && !is_int($default)) {
0 ignored issues
show
introduced by
The condition null !== $default is always false.
Loading history...
473 1
            throw new InvalidArgumentException(
474 1
                'Invalid default value ' . $default
475 1
                . ' with type ' . self::getType($default)
476
            );
477
        }
478 2
        foreach ($fields as $field) {
479 2
            $fieldBuilder = new FieldBuilder(
480 2
                $builder,
481
                [
482 2
                    'fieldName' => $field,
483 2
                    'type'      => Type::INTEGER,
484 2
                    'default'   => $default,
485
                ]
486
            );
487
            $fieldBuilder
488 2
                ->columnName(self::getColumnNameForField($field))
489 2
                ->nullable(null === $default)
490 2
                ->unique($isUnique)
491 2
                ->build();
492
        }
493 2
    }
494
495
    /**
496
     * Set bog standard boolean fields quickly in bulk
497
     *
498
     * @param array                $fields
499
     * @param ClassMetadataBuilder $builder
500
     * @param mixed                $default
501
     * In this case the boolean argument is simply data
502
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
503
     */
504 3
    public static function setSimpleBooleanFields(
505
        array $fields,
506
        ClassMetadataBuilder $builder,
507
        $default = null
508
    ): void {
509 3
        if (null !== $default && !is_bool($default)) {
510 1
            throw new InvalidArgumentException(
511 1
                'Invalid default value ' . $default
512 1
                . ' with type ' . self::getType($default)
513
            );
514
        }
515 2
        foreach ($fields as $field) {
516 2
            $fieldBuilder = new FieldBuilder(
517 2
                $builder,
518
                [
519 2
                    'fieldName' => $field,
520 2
                    'type'      => Type::BOOLEAN,
521 2
                    'default'   => $default,
522
                ]
523
            );
524
            $fieldBuilder
525 2
                ->columnName(self::getColumnNameForField($field))
526 2
                ->nullable(null === $default)
527 2
                ->build();
528
        }
529 2
    }
530
531
    /**
532
     * Create JSON Array fields
533
     *
534
     * Will use real JSON in the DB engine if it is supported
535
     *
536
     * This should be used for any structured data, arrays, lists, simple objects
537
     *
538
     * @param array                $fields
539
     * @param ClassMetadataBuilder $builder
540
     * @param array|null           $default
541
     */
542 2
    public static function setSimpleArrayFields(
543
        array $fields,
544
        ClassMetadataBuilder $builder,
545
        ?array $default = null
546
    ): void {
547 2
        foreach ($fields as $field) {
548 2
            $fieldBuilder = new FieldBuilder(
549 2
                $builder,
550
                [
551 2
                    'fieldName' => $field,
552 2
                    'type'      => Type::JSON_ARRAY,
553 2
                    'default'   => $default,
554
                ]
555
            );
556
            $fieldBuilder
557 2
                ->columnName(self::getColumnNameForField($field))
558 2
                ->nullable(null === $default)
559 2
                ->build();
560
        }
561 2
    }
562
563
    /**
564
     * Create JSON Object fields
565
     *
566
     * Will use real JSON in the DB engine if it is supported
567
     *
568
     * This should be used for any structured data, arrays, lists, simple objects
569
     *
570
     * @param array                $fields
571
     * @param ClassMetadataBuilder $builder
572
     * @param object|null          $default
573
     */
574 2
    public static function setSimpleObjectFields(
575
        array $fields,
576
        ClassMetadataBuilder $builder,
577
        ?object $default = null
578
    ): void {
579 2
        foreach ($fields as $field) {
580 2
            $fieldBuilder = new FieldBuilder(
581 2
                $builder,
582
                [
583 2
                    'fieldName' => $field,
584 2
                    'type'      => Type::JSON,
585 2
                    'default'   => $default,
586
                ]
587
            );
588
            $fieldBuilder
589 2
                ->columnName(self::getColumnNameForField($field))
590 2
                ->nullable(null === $default)
591 2
                ->build();
592
        }
593 2
    }
594
595
    /**
596
     * Bulk create multiple fields of different simple types
597
     *
598
     * Always creates nullable fields, if you want to set a default, you must call the type based method
599
     *
600
     * @param array                $fieldToType [
601
     *                                          'fieldName'=>'fieldSimpleType'
602
     *                                          ]
603
     * @param ClassMetadataBuilder $builder
604
     */
605 2
    public static function setSimpleFields(
606
        array $fieldToType,
607
        ClassMetadataBuilder $builder
608
    ): void {
609 2
        foreach ($fieldToType as $field => $type) {
610 2
            $method = "setSimple$type" . 'fields';
611 2
            static::$method([$field], $builder);
612
        }
613 2
    }
614
}
615