Failed Conditions
Push — master ( 2b713c...735d0a )
by Alex
16s queued 13s
created

TypeReferenceHelpers::asPrimitive()   D

Complexity

Conditions 39
Paths 41

Size

Total Lines 73
Code Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 39
eloc 58
nc 41
nop 0
dl 0
loc 73
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    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
6
namespace AlgoWeb\ODataMetadata\Helpers;
7
8
use AlgoWeb\ODataMetadata\Edm\Validation\EdmError;
9
use AlgoWeb\ODataMetadata\Edm\Validation\EdmErrorCode;
10
use AlgoWeb\ODataMetadata\EdmConstants;
11
use AlgoWeb\ODataMetadata\EdmUtil;
12
use AlgoWeb\ODataMetadata\Enums\PrimitiveTypeKind;
13
use AlgoWeb\ODataMetadata\Enums\TypeKind;
14
use AlgoWeb\ODataMetadata\Interfaces\IBinaryTypeReference;
15
use AlgoWeb\ODataMetadata\Interfaces\ICheckable;
16
use AlgoWeb\ODataMetadata\Interfaces\ICollectionType;
17
use AlgoWeb\ODataMetadata\Interfaces\ICollectionTypeReference;
18
use AlgoWeb\ODataMetadata\Interfaces\IComplexType;
19
use AlgoWeb\ODataMetadata\Interfaces\IComplexTypeReference;
20
use AlgoWeb\ODataMetadata\Interfaces\IDecimalTypeReference;
21
use AlgoWeb\ODataMetadata\Interfaces\IEntityReferenceType;
22
use AlgoWeb\ODataMetadata\Interfaces\IEntityReferenceTypeReference;
23
use AlgoWeb\ODataMetadata\Interfaces\IEntityType;
24
use AlgoWeb\ODataMetadata\Interfaces\IEntityTypeReference;
25
use AlgoWeb\ODataMetadata\Interfaces\IEnumType;
26
use AlgoWeb\ODataMetadata\Interfaces\IEnumTypeReference;
27
use AlgoWeb\ODataMetadata\Interfaces\ILocation;
28
use AlgoWeb\ODataMetadata\Interfaces\IPrimitiveType;
29
use AlgoWeb\ODataMetadata\Interfaces\IPrimitiveTypeReference;
30
use AlgoWeb\ODataMetadata\Interfaces\IRowType;
31
use AlgoWeb\ODataMetadata\Interfaces\IRowTypeReference;
32
use AlgoWeb\ODataMetadata\Interfaces\ISchemaElement;
33
use AlgoWeb\ODataMetadata\Interfaces\ISpatialTypeReference;
34
use AlgoWeb\ODataMetadata\Interfaces\IStringTypeReference;
35
use AlgoWeb\ODataMetadata\Interfaces\IStructuredTypeReference;
36
use AlgoWeb\ODataMetadata\Interfaces\ITemporalTypeReference;
37
use AlgoWeb\ODataMetadata\Interfaces\IType;
38
use AlgoWeb\ODataMetadata\Interfaces\ITypeReference;
39
use AlgoWeb\ODataMetadata\Library\EdmCollectionTypeReference;
40
use AlgoWeb\ODataMetadata\Library\EdmComplexTypeReference;
41
use AlgoWeb\ODataMetadata\Library\EdmEntityReferenceTypeReference;
42
use AlgoWeb\ODataMetadata\Library\EdmEntityTypeReference;
43
use AlgoWeb\ODataMetadata\Library\EdmEnumTypeReference;
44
use AlgoWeb\ODataMetadata\Library\EdmPrimitiveTypeReference;
45
use AlgoWeb\ODataMetadata\Library\EdmRowTypeReference;
46
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadBinaryTypeReference;
47
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadCollectionType;
48
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadComplexTypeReference;
49
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadDecimalTypeReference;
50
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadEntityReferenceType;
51
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadEntityTypeReference;
52
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadEnumType;
53
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadPrimitiveTypeReference;
54
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadRowType;
55
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadSpatialTypeReference;
56
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadStringTypeReference;
57
use AlgoWeb\ODataMetadata\Library\Internal\Bad\BadTemporalTypeReference;
58
use AlgoWeb\ODataMetadata\StringConst;
59
60
/**
61
 * Class TypeReferenceHelpers.
62
 * @package AlgoWeb\ODataMetadata\Helpers
63
 */
64
trait TypeReferenceHelpers
65
{
66
    /**
67
     * Gets the type kind of the type references definition.
68
     *
69
     * @return TypeKind the type kind of the reference
70
     */
71
    public function typeKind(): TypeKind
72
    {
73
        $typeDefinition = $this->getDefinition();
74
        return $typeDefinition !== null ? $typeDefinition->getTypeKind() : TypeKind::None();
75
    }
76
77
    /**
78
     * Gets the full name of the definition referred to by the type reference.
79
     *
80
     * @return string|null the full name of this references definition
81
     */
82
    public function fullName(): ?string
83
    {
84
        $namedDefinition = $this->getDefinition();
85
        return $namedDefinition instanceof ISchemaElement ? $namedDefinition->fullName() : null;
86
    }
87
88
    /**
89
     * Returns the primitive kind of the definition of this reference.
90
     *
91
     * @return PrimitiveTypeKind the primitive kind of the definition of this reference
92
     */
93
    public function primitiveKind(): PrimitiveTypeKind
94
    {
95
        $typeDefinition = $this->getDefinition();
96
        if (null === $typeDefinition || !$typeDefinition->getTypeKind()->isPrimitive()) {
97
            return PrimitiveTypeKind::None();
98
        }
99
        assert($typeDefinition instanceof IPrimitiveType);
100
        return $typeDefinition->getPrimitiveKind();
101
    }
102
103
    /**
104
     * Returns true if this reference refers to a collection.
105
     *
106
     * @return bool this reference refers to a collection
107
     */
108
    public function isCollection(): bool
109
    {
110
        return $this->typeKind()->isCollection();
111
    }
112
113
    /**
114
     * Returns true if this reference refers to an entity type.
115
     *
116
     * @return bool this reference refers to an entity type
117
     */
118
    public function isEntity(): bool
119
    {
120
        return $this->typeKind()->isEntity();
121
    }
122
123
    /**
124
     * Returns true if this reference refers to an entity type.
125
     *
126
     * @return bool This reference refers to an entity type.<
127
     */
128
    public function isEntityReference(): bool
129
    {
130
        return $this->typeKind()->isEntityReference();
131
    }
132
133
    /**
134
     * Returns true if this reference refers to a complex type.
135
     *
136
     * @return bool this reference refers to a complex type
137
     */
138
    public function isComplex(): bool
139
    {
140
        return $this->typeKind()->isComplex();
141
    }
142
143
    /**
144
     * Returns true if this reference refers to an enumeration type.
145
     *
146
     * @return bool this reference refers to an enumeration type
147
     */
148
    public function isEnum(): bool
149
    {
150
        return $this->typeKind()->isEnum();
151
    }
152
153
    /**
154
     * Returns true if this reference refers to a row type.
155
     *
156
     * @return bool this reference refers to a row type
157
     */
158
    public function isRow(): bool
159
    {
160
        return $this->typeKind()->isRow();
161
    }
162
163
    /**
164
     * Returns true if this reference refers to a structured type.
165
     *
166
     * @return bool this reference refers to a structured type
167
     */
168
    public function isStructured(): bool
169
    {
170
        return $this->typeKind()->IsStructured();
171
        /*switch ($this->TypeKind()) {
172
            case TypeKind::Entity():
173
            case TypeKind::Complex():
174
            case TypeKind::Row():
175
                return true;
176
        }
177
        return false;*/
178
    }
179
180
    /**
181
     * Returns true if this reference refers to a primitive type.
182
     *
183
     * @return bool this reference refers to a primitive type
184
     */
185
    public function isPrimitive(): bool
186
    {
187
        return $this->typeKind()->isPrimitive();
188
    }
189
    /**
190
     * Returns true if this reference refers to a binary type.
191
     *
192
     * @return bool this reference refers to a binary type
193
     */
194
    public function isBinary(): bool
195
    {
196
        return $this->primitiveKind()->isBinary();
197
    }
198
    /**
199
     * Returns true if this reference refers to a boolean type.
200
     *
201
     * @return bool this reference refers to a boolean type
202
     */
203
    public function isBoolean(): bool
204
    {
205
        return $this->primitiveKind()->equals(PrimitiveTypeKind::Boolean());
206
    }
207
208
    /**
209
     * Returns true if this reference refers to a temporal type.
210
     *
211
     * @return bool this reference refers to a temporal type
212
     */
213
    public function isTemporal(): bool
214
    {
215
        return $this->primitiveKind()->isTemporal();
216
    }
217
    /**
218
     * Returns true if this reference refers to a DateTime type.
219
     *
220
     * @return bool this reference refers to a DateTime type
221
     */
222
    public function isDateTime(): bool
223
    {
224
        return $this->primitiveKind()->isDateTime();
225
    }
226
227
    /**
228
     * Returns true if this reference refers to a time type.
229
     *
230
     * @return bool this reference refers to a time type
231
     */
232
    public function isTime(): bool
233
    {
234
        return $this->primitiveKind()->isTime();
235
    }
236
237
    /**
238
     * Returns true if this reference refers to a DateTimeOffset type.
239
     *
240
     * @return bool this reference refers to a DateTimeOffset type
241
     */
242
    public function isDateTimeOffset(): bool
243
    {
244
        return $this->primitiveKind()->isDateTimeOffset();
245
    }
246
247
    /**
248
     * Returns true if this reference refers to a decimal type.
249
     *
250
     * @return bool this reference refers to a decimal type
251
     */
252
    public function isDecimal(): bool
253
    {
254
        return $this->primitiveKind()->isDecimal();
255
    }
256
257
    /**
258
     * Returns true if this reference refers to a floating type.
259
     *
260
     * @return bool this reference refers to a floating type
261
     */
262
    public function isFloating(): bool
263
    {
264
        return $this->primitiveKind()->isAnyOf(
265
            PrimitiveTypeKind::Double(),
266
            PrimitiveTypeKind::Single()
267
        );
268
    }
269
    /**
270
     * Returns true if this reference refers to a single type.
271
     *
272
     * @return bool this reference refers to a single type
273
     */
274
    public function isSingle(): bool
275
    {
276
        return $this->primitiveKind()->isSingle();
277
    }
278
    /**
279
     * Returns true if this reference refers to a double type.
280
     *
281
     * @return bool this reference refers to a double type
282
     */
283
    public function isDouble(): bool
284
    {
285
        return $this->primitiveKind()->isDouble();
286
    }
287
288
    /**
289
     * Returns true if this reference refers to a GUID type.
290
     *
291
     * @return bool this reference refers to a GUID type
292
     */
293
    public function isGuid(): bool
294
    {
295
        return $this->primitiveKind()->isGuid();
296
    }
297
298
    /**
299
     * Returns true if this reference refers to a signed integral type.
300
     *
301
     * @return bool this reference refers to a signed integral type
302
     */
303
    public function isSignedIntegral(): bool
304
    {
305
        return $this->primitiveKind()->isSignedIntegral();
306
    }
307
308
    /**
309
     * Returns true if this reference refers to a SByte type.
310
     *
311
     * @return bool this reference refers to a SByte type
312
     */
313
    public function isSByte(): bool
314
    {
315
        return $this->primitiveKind()->isSByte();
316
    }
317
318
319
    /**
320
     * Returns true if this reference refers to a Int16 type.
321
     *
322
     * @return bool this reference refers to a Int16 type
323
     */
324
    public function isInt16(): bool
325
    {
326
        return $this->primitiveKind()->isInt16();
327
    }
328
    /**
329
     * Returns true if this reference refers to a Int32 type.
330
     *
331
     * @return bool this reference refers to a Int32 type
332
     */
333
    public function isInt32(): bool
334
    {
335
        return $this->primitiveKind()->isInt32();
336
    }
337
338
    /**
339
     * Returns true if this reference refers to a Int64 type.
340
     *
341
     * @return bool this reference refers to a Int64 type
342
     */
343
    public function isInt64(): bool
344
    {
345
        return $this->primitiveKind()->isInt64();
346
    }
347
348
    /**
349
     * Returns true if this reference refers to an integer type.
350
     *
351
     * @return bool this reference refers to an integer type
352
     */
353
    public function isIntegral(): bool
354
    {
355
        return $this->primitiveKind()->isIntegral();
356
    }
357
358
    /**
359
     * Returns true if this reference refers to a byte type.
360
     *
361
     * @return bool this reference refers to a byte type
362
     */
363
    public function isByte(): bool
364
    {
365
        return $this->primitiveKind()->isByte();
366
    }
367
    /**
368
     * Returns true if this reference refers to a string type.
369
     *
370
     * @return bool this reference refers to a string type
371
     */
372
    public function isString(): bool
373
    {
374
        return $this->primitiveKind()->isString();
375
    }
376
377
    /**
378
     * Returns true if this reference refers to a stream type.
379
     *
380
     * @return bool this reference refers to a stream type
381
     */
382
    public function isStream(): bool
383
    {
384
        return $this->primitiveKind()->isStream();
385
    }
386
387
    /**
388
     * Returns true if this reference refers to a spatial type.
389
     *
390
     * @return bool this reference refers to a spatial type
391
     */
392
    public function isSpatial(): bool
393
    {
394
        $primitiveTypeKind = $this->primitiveKind();
395
        return null === $primitiveTypeKind ? false : $primitiveTypeKind->IsSpatial();
396
    }
397
398
    // The As*** functions never return null -- if the supplied type does not have the appropriate shape, an encoding
399
    // of a bad type is returned.
400
401
    /**
402
     * If this reference is of a primitive type, this will return a valid primitive type reference to the type
403
     * definition. Otherwise, it will return a bad primitive type reference.
404
     *
405
     * @return IPrimitiveTypeReference A valid primitive type reference if the definition of the reference is of a
406
     *                                 primitive type. Otherwise a bad primitive type reference.
407
     */
408
    public function asPrimitive(): IPrimitiveTypeReference
409
    {
410
        if ($this instanceof IPrimitiveTypeReference) {
411
            return $this;
412
        }
413
414
        $typeDefinition = $this->getDefinition();
415
        if (null !== $typeDefinition && $typeDefinition->getTypeKind()->isPrimitive()) {
416
            if ($typeDefinition instanceof IPrimitiveType) {
417
                switch ($typeDefinition->getPrimitiveKind()) {
418
                    case PrimitiveTypeKind::Boolean():
419
                    case PrimitiveTypeKind::Byte():
420
                    case PrimitiveTypeKind::Double():
421
                    case PrimitiveTypeKind::Guid():
422
                    case PrimitiveTypeKind::Int16():
423
                    case PrimitiveTypeKind::Int32():
424
                    case PrimitiveTypeKind::Int64():
425
                    case PrimitiveTypeKind::SByte():
426
                    case PrimitiveTypeKind::Single():
427
                    case PrimitiveTypeKind::Stream():
428
                        return new EdmPrimitiveTypeReference($typeDefinition, $this->getNullable());
429
                    case PrimitiveTypeKind::Binary():
430
                        return $this->asBinary();
431
                    case PrimitiveTypeKind::Decimal():
432
                        return $this->asDecimal();
433
                    case PrimitiveTypeKind::String():
434
                        return $this->asString();
435
                    case PrimitiveTypeKind::Time():
436
                    case PrimitiveTypeKind::DateTime():
437
                    case PrimitiveTypeKind::DateTimeOffset():
438
                        return $this->asTemporal();
439
                    case PrimitiveTypeKind::Geography():
440
                    case PrimitiveTypeKind::GeographyPoint():
441
                    case PrimitiveTypeKind::GeographyLineString():
442
                    case PrimitiveTypeKind::GeographyPolygon():
443
                    case PrimitiveTypeKind::GeographyCollection():
444
                    case PrimitiveTypeKind::GeographyMultiPoint():
445
                    case PrimitiveTypeKind::GeographyMultiLineString():
446
                    case PrimitiveTypeKind::GeographyMultiPolygon():
447
                    case PrimitiveTypeKind::Geometry():
448
                    case PrimitiveTypeKind::GeometryPoint():
449
                    case PrimitiveTypeKind::GeometryLineString():
450
                    case PrimitiveTypeKind::GeometryPolygon():
451
                    case PrimitiveTypeKind::GeometryCollection():
452
                    case PrimitiveTypeKind::GeometryMultiPolygon():
453
                    case PrimitiveTypeKind::GeometryMultiLineString():
454
                    case PrimitiveTypeKind::GeometryMultiPoint():
455
                        return $this->asSpatial();
456
                    case PrimitiveTypeKind::None():
457
                        break;
458
                }
459
            }
460
        }
461
462
        $typeFullName = $this->fullName();
463
        $errors       = [];
464
        if ($this instanceof ICheckable) {
465
            $errors = $this->getErrors();
466
            $errors = iterable_to_array($errors);
467
        }
468
        //if (count($errors) == 0)
469
        {
470
            $errors = array_merge(
471
                $errors,
472
                self::conversionError(
473
                    $this->location(),
474
                    $typeFullName,
475
                    EdmConstants::Type_Primitive
476
                )
477
            );
478
        }
479
480
        return new BadPrimitiveTypeReference($typeFullName, $this->getNullable(), $errors);
481
    }
482
483
    /**
484
     * If this reference is of a collection type, this will return a valid collection type reference to the type
485
     * definition. Otherwise, it will return a bad collection type reference.
486
     *
487
     * @return ICollectionTypeReference A valid collection type reference if the definition of the reference is of a
488
     *                                  collection type. Otherwise a bad collection type reference.
489
     */
490
    public function asCollection(): ICollectionTypeReference
491
    {
492
        if ($this instanceof ICollectionTypeReference) {
493
            return $this;
494
        }
495
        $type = $this;
496
497
        $typeDefinition = $type->getDefinition();
498
        if ($typeDefinition->getTypeKind()->isCollection()) {
499
            assert($typeDefinition instanceof ICollectionType);
500
            return new EdmCollectionTypeReference($typeDefinition, $type->getNullable());
501
        }
502
        $errors = [];
503
        if ($this instanceof ICheckable) {
504
            $errors = $this->getErrors();
505
            $errors = iterable_to_array($errors);
506
        }
507
508
        if (count($errors) == 0) {
509
            $errors = array_merge(
510
                $errors,
511
                self::conversionError(
512
                    $type->location(),
513
                    $type->fullName(),
514
                    EdmConstants::Type_Collection
515
                )
516
            );
517
        }
518
519
        return new EdmCollectionTypeReference(new BadCollectionType($errors), $type->getNullable());
520
    }
521
522
    /**
523
     * If this reference is of a structured type, this will return a valid structured type reference to the type
524
     * definition. Otherwise, it will return a bad structured type reference.
525
     *
526
     * @return IStructuredTypeReference A valid structured type reference if the definition of the reference is of a
527
     *                                  structured type. Otherwise a bad structured type reference.
528
     */
529
    public function asStructured(): IStructuredTypeReference
530
    {
531
        if ($this instanceof IStructuredTypeReference) {
532
            return $this;
533
        }
534
535
        switch ($this->typeKind()) {
536
            case TypeKind::Entity():
537
                return $this->asEntity();
538
            case TypeKind::Complex():
539
                return $this->asComplex();
540
            case TypeKind::Row():
541
                return $this->asRow();
542
        }
543
544
        $typeFullName = $this->fullName();
545
        EdmUtil::checkArgumentNull($typeFullName, 'typeFullName');
546
547
        $errors = [];
548
        if ($this instanceof ICheckable) {
549
            $errors = $this->getErrors();
550
            $errors = iterable_to_array($errors);
551
        }
552
553
        if (count($errors) == 0) {
554
            $errors = array_merge(
555
                $errors,
556
                self::conversionError(
557
                    $this->location(),
558
                    $typeFullName,
559
                    EdmConstants::Type_Structured
560
                )
561
            );
562
        }
563
564
        return new BadEntityTypeReference($typeFullName, $this->getNullable(), $errors);
565
    }
566
567
    /**
568
     * If this reference is of an enumeration type, this will return a valid enumeration type reference to the type
569
     * definition. Otherwise, it will return a bad enumeration type reference.
570
     *
571
     * @return IEnumTypeReference A valid enumeration type reference if the definition of the reference is of an
572
     *                            enumeration type. Otherwise a bad enumeration type reference.
573
     */
574
    public function asEnum(): IEnumTypeReference
575
    {
576
        if ($this instanceof IEnumTypeReference) {
577
            return $this;
578
        }
579
580
        $typeDefinition = $this->getDefinition();
581
        if ($typeDefinition->getTypeKind()->isEnum()) {
582
            assert($typeDefinition instanceof IEnumType);
583
            return new EdmEnumTypeReference($typeDefinition, $this->getNullable());
584
        }
585
586
        $typeFullName = $this->fullName();
587
        return new EdmEnumTypeReference(
588
            new BadEnumType(
589
                $typeFullName,
590
                self::conversionError(
591
                    $this->location(),
592
                    $typeFullName,
593
                    EdmConstants::Type_Enum
594
                )
595
            ),
596
            $this->getNullable()
597
        );
598
    }
599
600
    /**
601
     * If this reference is of an entity type, this will return a valid entity type reference to the type definition.
602
     * Otherwise, it will return a bad entity type reference.
603
     *
604
     * @return IEntityTypeReference A valid entity type reference if the definition of the reference is of an entity
605
     *                              type. Otherwise a bad entity type reference.
606
     */
607
    public function asEntity(): IEntityTypeReference
608
    {
609
        if ($this instanceof IEntityTypeReference) {
610
            return $this;
611
        }
612
613
        $typeDefinition = $this->getDefinition();
614
        if ($typeDefinition->getTypeKind()->isEntity()) {
615
            assert($typeDefinition instanceof IEntityType);
616
            return new EdmEntityTypeReference($typeDefinition, $this->getNullable());
617
        }
618
        $typeFullName = $this->fullName();
619
        EdmUtil::checkArgumentNull($typeFullName, 'typeFullName');
620
621
        $errors = [];
622
        if ($this instanceof ICheckable) {
623
            $errors = $this->getErrors();
624
            $errors = iterable_to_array($errors);
625
        }
626
627
        if (count($errors) == 0) {
628
            $errors = array_merge(
629
                $errors,
630
                self::conversionError(
631
                    $this->location(),
632
                    $typeFullName,
633
                    EdmConstants::Type_Entity
634
                )
635
            );
636
        }
637
638
        return new BadEntityTypeReference($typeFullName, $this->getNullable(), $errors);
639
    }
640
641
    /**
642
     * If this reference is of an entity reference type, this will return a valid entity reference type reference to
643
     * the type definition. Otherwise, it will return a bad entity reference type reference.
644
     *
645
     * @return IEntityReferenceTypeReference A valid entity reference type reference if the definition of the reference
646
     *                                       is of an entity reference type. Otherwise a bad entity reference type
647
     *                                       reference.
648
     */
649
    public function asEntityReference(): IEntityReferenceTypeReference
650
    {
651
        if ($this instanceof IEntityReferenceTypeReference) {
652
            return $this;
653
        }
654
655
        $typeDefinition = $this->getDefinition();
656
        if ($typeDefinition->getTypeKind()->isEntityReference()) {
657
            assert($typeDefinition instanceof IEntityReferenceType);
658
            return new EdmEntityReferenceTypeReference($typeDefinition, $this->getNullable());
659
        }
660
661
        $errors = [];
662
        if ($this instanceof ICheckable) {
663
            $errors = $this->getErrors();
664
            $errors = iterable_to_array($errors);
665
        }
666
667
        if (count($errors) == 0) {
668
            $errors = array_merge(
669
                $errors,
670
                self::conversionError(
671
                    $this->location(),
672
                    $this->fullName(),
673
                    EdmConstants::Type_EntityReference
674
                )
675
            );
676
        }
677
678
        return new EdmEntityReferenceTypeReference(new BadEntityReferenceType($errors), $this->getNullable());
679
    }
680
681
    /**
682
     * If this reference is of a complex type, this will return a valid complex type reference to the type definition.
683
     * Otherwise, it will return a bad complex type reference.
684
     *
685
     * @return IComplexTypeReference A valid complex type reference if the definition of the reference is of a complex
686
     *                               type. Otherwise a bad complex type reference.
687
     */
688
    public function asComplex(): IComplexTypeReference
689
    {
690
        if ($this instanceof IComplexTypeReference) {
691
            return $this;
692
        }
693
694
        $typeDefinition = $this->getDefinition();
695
        if ($typeDefinition->getTypeKind()->isComplex()) {
696
            assert($typeDefinition instanceof IComplexType);
697
            return new EdmComplexTypeReference($typeDefinition, $this->getNullable());
698
        }
699
700
        $typeFullName = $this->fullName();
701
        EdmUtil::checkArgumentNull($typeFullName, 'typeFullName');
702
703
        $errors       = [];
704
        if ($this instanceof ICheckable) {
705
            $errors = $this->getErrors();
706
            $errors = iterable_to_array($errors);
707
        }
708
709
        if (count($errors) == 0) {
710
            $errors = array_merge(
711
                $errors,
712
                self::conversionError(
713
                    $this->location(),
714
                    $this->fullName(),
715
                    EdmConstants::Type_Complex
716
                )
717
            );
718
        }
719
720
        return new BadComplexTypeReference($typeFullName, $this->getNullable(), $errors);
721
    }
722
723
    /**
724
     * If this reference is of a row type, this will return a valid row type reference to the type definition.
725
     * Otherwise, it will return a bad row type reference.
726
     *
727
     * @return IRowTypeReference A valid row type reference if the definition of the reference is of a row type.
728
     *                           Otherwise a bad row type reference.
729
     */
730
    public function asRow(): IRowTypeReference
731
    {
732
        if ($this instanceof IRowTypeReference) {
733
            return $this;
734
        }
735
736
        $typeDefinition = $this->getDefinition();
737
        if ($typeDefinition->getTypeKind()->isRow()) {
738
            assert($typeDefinition instanceof IRowType);
739
            return new EdmRowTypeReference($typeDefinition, $this->getNullable());
740
        }
741
742
        $errors = [];
743
        if ($this instanceof ICheckable) {
744
            $errors = $this->getErrors();
745
            $errors = iterable_to_array($errors);
746
        }
747
748
        if (count($errors) == 0) {
749
            $errors = array_merge(
750
                $errors,
751
                self::conversionError(
752
                    $this->location(),
753
                    $this->fullName(),
754
                    EdmConstants::Type_Row
755
                )
756
            );
757
        }
758
759
        return new EdmRowTypeReference(new BadRowType($errors), $this->getNullable());
760
    }
761
762
    /**
763
     * If this reference is of a spatial type, this will return a valid spatial type reference to the type definition.
764
     * Otherwise, it will return a bad spatial type reference.
765
     *
766
     * @return ISpatialTypeReference A valid spatial type reference if the definition of the reference is of a spatial
767
     *                               type. Otherwise a bad spatial type reference.
768
     */
769
    public function asSpatial(): ISpatialTypeReference
770
    {
771
        if ($this instanceof ISpatialTypeReference) {
772
            return $this;
773
        }
774
775
        $typeFullName = $this->fullName();
776
        EdmUtil::checkArgumentNull($typeFullName, 'typeFullName');
777
778
        $errors       = [];
779
        if ($this instanceof ICheckable) {
780
            $errors = $this->getErrors();
781
            $errors = iterable_to_array($errors);
782
        }
783
784
        if (count($errors) == 0) {
785
            $errors = array_merge(
786
                $errors,
787
                self::conversionError(
788
                    $this->location(),
789
                    $this->fullName(),
790
                    EdmConstants::Type_Spatial
791
                )
792
            );
793
        }
794
795
        return new BadSpatialTypeReference($typeFullName, $this->getNullable(), $errors);
796
    }
797
798
    /**
799
     * If this reference is of a temporal type, this will return a valid temporal type reference to the type definition.
800
     * Otherwise, it will return a bad temporal type reference.
801
     *
802
     * @return ITemporalTypeReference A valid temporal type reference if the definition of the reference is of a
803
     *                                temporal type. Otherwise a bad temporal type reference.
804
     */
805
    public function asTemporal(): ITemporalTypeReference
806
    {
807
        if ($this instanceof ITemporalTypeReference) {
808
            return $this;
809
        }
810
811
        $typeFullName = $this->fullName();
812
        EdmUtil::checkArgumentNull($typeFullName, 'typeFullName');
813
814
        $errors       = [];
815
        if ($this instanceof ICheckable) {
816
            $errors = $this->getErrors();
817
            $errors = iterable_to_array($errors);
818
        }
819
820
        if (count($errors) == 0) {
821
            $errors = array_merge(
822
                $errors,
823
                self::conversionError(
824
                    $this->location(),
825
                    $this->fullName(),
826
                    EdmConstants::Type_Temporal
827
                )
828
            );
829
        }
830
831
        return new BadTemporalTypeReference($typeFullName, $this->getNullable(), $errors);
832
    }
833
834
    /**
835
     * If this reference is of a decimal type, this will return a valid decimal type reference to the type definition.
836
     * Otherwise, it will return a bad decimal type reference.
837
     *
838
     * @return IDecimalTypeReference A valid decimal type reference if the definition of the reference is of a decimal
839
     *                               type. Otherwise a bad decimal type reference.</returns>
840
     */
841
    public function asDecimal(): IDecimalTypeReference
842
    {
843
        if ($this instanceof IDecimalTypeReference) {
844
            return $this;
845
        }
846
847
        $typeFullName = $this->fullName();
848
        EdmUtil::checkArgumentNull($typeFullName, 'typeFullName');
849
850
        $errors       = [];
851
        if ($this instanceof ICheckable) {
852
            $errors = $this->getErrors();
853
            $errors = iterable_to_array($errors);
854
        }
855
856
        if (count($errors) == 0) {
857
            $errors = array_merge(
858
                $errors,
859
                self::conversionError(
860
                    $this->location(),
861
                    $typeFullName,
862
                    EdmConstants::Type_Decimal
863
                )
864
            );
865
        }
866
867
        return new BadDecimalTypeReference($typeFullName, $this->getNullable(), $errors);
868
    }
869
870
    /**
871
     * If this reference is of a string type, this will return a valid string type reference to the type definition.
872
     * Otherwise, it will return a bad string type reference.
873
     *
874
     * @return IStringTypeReference A valid string type reference if the definition of the reference is of a string
875
     *                              type. Otherwise a bad string type reference.
876
     */
877
    public function asString(): IStringTypeReference
878
    {
879
        if ($this instanceof IStringTypeReference) {
880
            return $this;
881
        }
882
883
        $typeFullName = $this->fullName();
884
        EdmUtil::checkArgumentNull($typeFullName, 'typeFullName');
885
886
        $errors       = [];
887
        if ($this instanceof ICheckable) {
888
            $errors = $this->getErrors();
889
            $errors = iterable_to_array($errors);
890
        }
891
892
        if (count($errors) == 0) {
893
            $errors = array_merge(
894
                $errors,
895
                self::conversionError(
896
                    $this->location(),
897
                    $typeFullName,
898
                    EdmConstants::Type_String
899
                )
900
            );
901
        }
902
903
        return new BadStringTypeReference($typeFullName, $this->getNullable(), $errors);
904
    }
905
906
    /**
907
     * If this reference is of a binary type, this will return a valid binary type reference to the type definition.
908
     * Otherwise, it will return a bad binary type reference.
909
     *
910
     * @return IBinaryTypeReference A valid binary type reference if the definition of the reference is of a binary
911
     *                              type. Otherwise a bad binary type reference.
912
     */
913
    public function asBinary(): IBinaryTypeReference
914
    {
915
        if ($this instanceof IBinaryTypeReference) {
916
            return $this;
917
        }
918
        $typeFullName = $this->fullName();
919
        EdmUtil::checkArgumentNull($typeFullName, 'typeFullName');
920
921
        $errors       = [];
922
        if ($this instanceof ICheckable) {
923
            $errors = $this->getErrors();
924
            $errors = iterable_to_array($errors);
925
        }
926
927
        if (count($errors) == 0) {
928
            $errors = array_merge(
929
                $errors,
930
                self::conversionError(
931
                    $this->location(),
932
                    $typeFullName,
933
                    EdmConstants::Type_Binary
934
                )
935
            );
936
        }
937
938
        return new BadBinaryTypeReference($typeFullName, $this->getNullable(), $errors);
939
    }
940
941
942
    /**
943
     * @param  ILocation|null $location
944
     * @param  string         $typeName
945
     * @param  string         $typeKindName
946
     * @return EdmError[]
947
     */
948
    private static function conversionError(?ILocation $location, ?string $typeName, string $typeKindName): array
949
    {
950
        return [
951
            new EdmError(
952
                $location,
953
                EdmErrorCode::TypeSemanticsCouldNotConvertTypeReference(),
954
                StringConst::TypeSemantics_CouldNotConvertTypeReference(
955
                    $typeName ?? EdmConstants::Value_UnnamedType,
956
                    $typeKindName
957
                )
958
            )
959
        ];
960
    }
961
962
    abstract public function getDefinition(): ?IType;
963
964
    abstract public function getNullable(): bool;
965
966
    abstract public function location(): ?ILocation;
967
}
968