TypeReferenceHelpers::isSpatial()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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