Test Setup Failed
Push — master ( 0a3e88...820bc9 )
by Christopher
04:41
created

ResourceType::getNamespace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace POData\Providers\Metadata;
4
5
use InvalidArgumentException;
6
use POData\Common\InvalidOperationException;
7
use POData\Common\Messages;
8
use POData\Providers\Metadata\Type\Binary;
9
use POData\Providers\Metadata\Type\Boolean;
10
use POData\Providers\Metadata\Type\Byte;
11
use POData\Providers\Metadata\Type\DateTime;
12
use POData\Providers\Metadata\Type\Decimal;
13
use POData\Providers\Metadata\Type\Double;
14
use POData\Providers\Metadata\Type\EdmPrimitiveType;
15
use POData\Providers\Metadata\Type\Guid;
16
use POData\Providers\Metadata\Type\Int16;
17
use POData\Providers\Metadata\Type\Int32;
18
use POData\Providers\Metadata\Type\Int64;
19
use POData\Providers\Metadata\Type\IType;
20
use POData\Providers\Metadata\Type\SByte;
21
use POData\Providers\Metadata\Type\Single;
22
use POData\Providers\Metadata\Type\StringType;
23
24
/**
25
 * Class ResourceType.
26
 *
27
 * A type to describe an entity type, complex type or primitive type.
28
 */
29
abstract class ResourceType
30
{
31
    /**
32
     * Name of the resource described by this class instance.
33
     *
34
     * @var string
35
     */
36
    private $name;
37
38
    /**
39
     * Namespace name in which resource described by this class instance
40
     * belongs to.
41
     *
42
     * @var string
43
     */
44
    private $namespaceName;
45
46
    /**
47
     * The fully qualified name of the resource described by this class instance.
48
     *
49
     * @var string
50
     */
51
    private $fullName;
52
53
    /**
54
     * The type the resource described by this class instance.
55
     * Note: either Entity or Complex Type.
56
     *
57
     * @var ResourceTypeKind
58
     */
59
    protected $resourceTypeKind;
60
61
    /**
62
     * @var bool
63
     */
64
    private $abstractType;
65
66
    /**
67
     * Refrence to ResourceType instance for base type, if any.
68
     *
69
     * @var ResourceType
70
     */
71
    private $baseType;
72
73
    /**
74
     * Collection of ResourceProperty for all properties declared on the
75
     * resource described by this class instance (This does not include
76
     * base type properties).
77
     *
78
     * @var ResourceProperty[] indexed by name
79
     */
80
    private $propertiesDeclaredOnThisType = [];
81
82
    /**
83
     * Collection of ResourceStreamInfo for all named streams declared on
84
     * the resource described by this class instance (This does not include
85
     * base type properties).
86
     *
87
     * @var ResourceStreamInfo[] indexed by name
88
     */
89
    private $namedStreamsDeclaredOnThisType = [];
90
91
    /**
92
     * Collection of ResourceProperty for all properties declared on this type.
93
     * and base types.
94
     *
95
     * @var ResourceProperty[] indexed by name
96
     */
97
    private $allProperties = [];
98
99
    /**
100
     * Collection of ResourceStreamInfo for all named streams declared on this type.
101
     * and base types.
102
     *
103
     * @var ResourceStreamInfo[]
104
     */
105
    private $allNamedStreams = [];
106
107
    /**
108
     * Collection of properties which has etag defined subset of $_allProperties.
109
     *
110
     * @var ResourceProperty[]
111
     */
112
    private $eTagProperties = [];
113
114
    /**
115
     * Collection of key properties subset of $_allProperties.
116
     *
117
     * @var ResourceProperty[]
118
     */
119
    private $keyProperties = [];
120
121
    /**
122
     * Whether the resource type described by this class instance is a MLE or not.
123
     *
124
     * @var bool
125
     */
126
    private $isMediaLinkEntry = false;
127
128
    /**
129
     * Whether the resource type described by this class instance has bag properties
130
     * Note: This has been initialized with null, later in hasBagProperty method,
131
     * this flag will be set to boolean value.
132
     *
133
     * @var bool
134
     */
135
    private $hasBagProperty = null;
136
137
    /**
138
     * Whether the resource type described by this class instance has named streams
139
     * Note: This has been intitialized with null, later in hasNamedStreams method,
140
     * this flag will be set to boolean value.
141
     *
142
     * @var bool
143
     */
144
    private $hasNamedStreams = null;
145
146
    /**
147
     * ReflectionClass (for complex/Entity) or IType (for Primitive) instance for
148
     * the resource (type) described by this class instance.
149
     *
150
     * @var \ReflectionClass|IType|string
151
     */
152
    private $type;
153
154
    /**
155
     * To store any custom information related to this class instance.
156
     *
157
     * @var object
158
     */
159
    private $customState;
160
161
    /**
162
     * Array to detect looping in bag's complex type.
163
     *
164
     * @var array
165
     */
166
    private $arrayToDetectLoopInComplexBag;
167
168
    /**
169
     * Create new instance of ResourceType.
170
     *
171
     * @param \ReflectionClass|IType $instanceType     Instance type for the resource,
172
     *                                                 for entity and
173
     *                                                 complex this will
174
     *                                                 be 'ReflectionClass' and for
175
     *                                                 primitive type this
176
     *                                                 will be IType
177
     * @param ResourceTypeKind       $resourceTypeKind Kind of resource (Entity, Complex or Primitive)
178
     * @param string                 $name             Name of the resource
179
     * @param string                 $namespaceName    Namespace of the resource
180
     * @param ResourceType           $baseType         Base type of the resource, if exists
181
     * @param bool                   $isAbstract       Whether resource is abstract
182
     *
183
     * @throws \InvalidArgumentException
184
     */
185
    protected function __construct(
186
        $instanceType,
187
        $resourceTypeKind,
188
        $name,
189
        $namespaceName = null,
190
        ResourceType $baseType = null,
191
        $isAbstract = false
192
    ) {
193
        $this->type = $instanceType;
194
        $this->resourceTypeKind = $resourceTypeKind;
195
        $this->name = $name;
196
        $this->baseType = $baseType;
197
        $this->namespaceName = $namespaceName;
198
        $this->fullName = is_null($namespaceName) ? $name : $namespaceName . '.' . $name;
199
        $this->abstractType = $isAbstract;
200
        $this->isMediaLinkEntry = false;
201
        $this->customState = null;
202
        $this->arrayToDetectLoopInComplexBag = [];
203
        //TODO: Set MLE if base type has MLE Set
204
    }
205
206
    /**
207
     * Get reference to ResourceType for base class.
208
     *
209
     * @return ResourceType
210
     */
211
    public function getBaseType()
212
    {
213
        return $this->baseType;
214
    }
215
216
    /**
217
     * To check whether this resource type has base type.
218
     *
219
     * @return bool True if base type is defined, false otherwise
220
     */
221
    public function hasBaseType()
222
    {
223
        return !is_null($this->baseType);
224
    }
225
226
    /**
227
     * To get custom state object for this type.
228
     *
229
     * @return object
230
     */
231
    public function getCustomState()
232
    {
233
        return $this->customState;
234
    }
235
236
    /**
237
     * To set custom state object for this type.
238
     *
239
     * @param ResourceSet $object The custom object
240
     */
241
    public function setCustomState($object)
242
    {
243
        $this->customState = $object;
244
    }
245
246
    /**
247
     * Get the instance type. If the resource type describes a complex or entity type,
248
     * then this function returns reference to ReflectionClass instance for the type.
249
     * If resource type describes a primitive type, then this function returns ITYpe.
250
     *
251
     * @return \ReflectionClass|IType
252
     */
253
    public function getInstanceType()
254
    {
255
        if (is_string($this->type)) {
256
            $this->__wakeup();
257
        }
258
259
        return $this->type;
260
    }
261
262
    /**
263
     * Get name of the type described by this resource type.
264
     *
265
     * @return string
266
     */
267
    public function getName()
268
    {
269
        return $this->name;
270
    }
271
272
    /**
273
     * Get the namespace under which the type described by this resource type is
274
     * defined.
275
     *
276
     * @return string
277
     */
278
    public function getNamespace()
279
    {
280
        return $this->namespaceName;
281
    }
282
283
    /**
284
     * Get full name (namespacename.typename) of the type described by this resource
285
     * type.
286
     *
287
     * @return string
288
     */
289
    public function getFullName()
290
    {
291
        return $this->fullName;
292
    }
293
294
    /**
295
     * To check whether the type described by this resource type is abstract or not.
296
     *
297
     * @return bool True if type is abstract else False
298
     */
299
    public function isAbstract()
300
    {
301
        return $this->abstractType;
302
    }
303
304
    /**
305
     * To get the kind of type described by this resource class.
306
     *
307
     * @return ResourceTypeKind
308
     */
309
    public function getResourceTypeKind()
310
    {
311
        return $this->resourceTypeKind;
312
    }
313
314
    /**
315
     * To check whether the type described by this resource type is MLE.
316
     *
317
     * @return bool True if type is MLE else False
318
     */
319
    public function isMediaLinkEntry()
320
    {
321
        return $this->isMediaLinkEntry;
322
    }
323
324
    /**
325
     * Set the resource type as MLE or non-MLE.
326
     *
327
     * @param bool $isMLE True to set as MLE, false for non-MLE
328
     */
329
    public function setMediaLinkEntry($isMLE)
330
    {
331
        if (ResourceTypeKind::ENTITY != $this->resourceTypeKind) {
332
            throw new InvalidOperationException(
333
                Messages::resourceTypeHasStreamAttributeOnlyAppliesToEntityType()
334
            );
335
        }
336
337
        $this->isMediaLinkEntry = $isMLE;
338
    }
339
340
    /**
341
     * Add a property belongs to this resource type instance.
342
     *
343
     * @param ResourceProperty $property Property to add
344
     * @param bool             $throw    Throw exception on name collision?
345
     *
346
     * @throws InvalidOperationException
347
     */
348
    public function addProperty(ResourceProperty $property, $throw = true)
349
    {
350
        if (ResourceTypeKind::PRIMITIVE == $this->resourceTypeKind) {
351
            throw new InvalidOperationException(
352
                Messages::resourceTypeNoAddPropertyForPrimitive()
353
            );
354
        }
355
356
        $name = $property->getName();
357 View Code Duplication
        foreach (array_keys($this->propertiesDeclaredOnThisType) as $propertyName) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
358
            if (0 == strcasecmp($propertyName, $name)) {
359
                if (false === $throw) {
360
                    return;
361
                }
362
                throw new InvalidOperationException(
363
                    Messages::resourceTypePropertyWithSameNameAlreadyExists(
364
                        $propertyName,
365
                        $this->name
366
                    )
367
                );
368
            }
369
        }
370
371
        if ($property->isKindOf(ResourcePropertyKind::KEY)) {
372
            if (ResourceTypeKind::ENTITY != $this->resourceTypeKind) {
373
                throw new InvalidOperationException(
374
                    Messages::resourceTypeKeyPropertiesOnlyOnEntityTypes()
375
                );
376
            }
377
378
            if (null != $this->baseType) {
379
                throw new InvalidOperationException(
380
                    Messages::resourceTypeNoKeysInDerivedTypes()
381
                );
382
            }
383
        }
384
385
        if ($property->isKindOf(ResourcePropertyKind::ETAG)
386
            && (ResourceTypeKind::ENTITY != $this->resourceTypeKind)
387
        ) {
388
            throw new InvalidOperationException(
389
                Messages::resourceTypeETagPropertiesOnlyOnEntityTypes()
390
            );
391
        }
392
393
        //Check for Base class properties
394
        $this->propertiesDeclaredOnThisType[$name] = $property;
395
        // Set $this->allProperties to null, this is very important because the
396
        // first call to getAllProperties will initilaize $this->allProperties,
397
        // further call to getAllProperties will not reinitialize _allProperties
398
        // so if addProperty is called after calling getAllProperties then the
399
        // property just added will not be reflected in $this->allProperties
400
        unset($this->allProperties);
401
        $this->allProperties = [];
402
    }
403
404
    /**
405
     * Get collection properties belongs to this resource type (excluding base class
406
     * properties). This function returns  empty array in case of resource type
407
     * for primitive types.
408
     *
409
     * @return ResourceProperty[]
410
     */
411
    public function getPropertiesDeclaredOnThisType()
412
    {
413
        return $this->propertiesDeclaredOnThisType;
414
    }
415
416
    /**
417
     * Get collection properties belongs to this resource type including base class
418
     * properties. This function returns  empty array in case of resource type
419
     * for primitive types.
420
     *
421
     * @return ResourceProperty[]
422
     */
423
    public function getAllProperties()
424
    {
425
        if (empty($this->allProperties)) {
426
            if (null != $this->baseType) {
427
                $this->allProperties = $this->baseType->getAllProperties();
428
            }
429
430
            $this->allProperties = array_merge(
431
                $this->allProperties, $this->propertiesDeclaredOnThisType
432
            );
433
        }
434
435
        return $this->allProperties;
436
    }
437
438
    /**
439
     * Get collection key properties belongs to this resource type. This
440
     * function returns non-empty array only for resource type representing
441
     * an entity type.
442
     *
443
     * @return ResourceProperty[]
444
     */
445
    public function getKeyProperties()
446
    {
447
        if (empty($this->keyProperties)) {
448
            $baseType = $this;
449
            while (null != $baseType->baseType) {
450
                $baseType = $baseType->baseType;
451
            }
452
453
            foreach ($baseType->propertiesDeclaredOnThisType as $propertyName => $resourceProperty) {
454
                if ($resourceProperty->isKindOf(ResourcePropertyKind::KEY)) {
455
                    $this->keyProperties[$propertyName] = $resourceProperty;
456
                }
457
            }
458
        }
459
460
        return $this->keyProperties;
461
    }
462
463
    /**
464
     * Get collection of e-tag properties belongs to this type.
465
     *
466
     * @return ResourceProperty[]
467
     */
468
    public function getETagProperties()
469
    {
470
        if (empty($this->eTagProperties)) {
471
            foreach ($this->getAllProperties() as $propertyName => $resourceProperty) {
472
                if ($resourceProperty->isKindOf(ResourcePropertyKind::ETAG)) {
473
                    $this->eTagProperties[$propertyName] = $resourceProperty;
474
                }
475
            }
476
        }
477
478
        return $this->eTagProperties;
479
    }
480
481
    /**
482
     * To check this type has any eTag properties.
483
     *
484
     * @return bool
485
     */
486
    public function hasETagProperties()
487
    {
488
        $properties = $this->getETagProperties();
489
490
        return !empty($properties);
491
    }
492
493
    /**
494
     * Try to get ResourceProperty for a property defined for this resource type
495
     * excluding base class properties.
496
     *
497
     * @param string $propertyName The name of the property to resolve
498
     *
499
     * @return ResourceProperty|null
500
     */
501
    public function resolvePropertyDeclaredOnThisType($propertyName)
502
    {
503
        if (array_key_exists($propertyName, $this->propertiesDeclaredOnThisType)) {
504
            return $this->propertiesDeclaredOnThisType[$propertyName];
505
        }
506
        return null;
507
    }
508
509
    /**
510
     * Try to get ResourceProperty for a property defined for this resource type
511
     * including base class properties.
512
     *
513
     * @param string $propertyName The name of the property to resolve
514
     *
515
     * @return ResourceProperty|null
516
     */
517
    public function resolveProperty($propertyName)
518
    {
519
        if (array_key_exists($propertyName, $this->getAllProperties())) {
520
            return $this->allProperties[$propertyName];
521
        }
522
        return null;
523
    }
524
525
    /**
526
     * Add a named stream belongs to this resource type instance.
527
     *
528
     * @param ResourceStreamInfo $namedStream ResourceStreamInfo instance describing the named stream to add
529
     *
530
     * @throws InvalidOperationException
531
     */
532
    public function addNamedStream(ResourceStreamInfo $namedStream)
533
    {
534
        if ($this->resourceTypeKind != ResourceTypeKind::ENTITY) {
535
            throw new InvalidOperationException(
536
                Messages::resourceTypeNamedStreamsOnlyApplyToEntityType()
537
            );
538
        }
539
540
        $name = $namedStream->getName();
541 View Code Duplication
        foreach (array_keys($this->namedStreamsDeclaredOnThisType) as $namedStreamName) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
542
            if (0 == strcasecmp($namedStreamName, $name)) {
543
                throw new InvalidOperationException(
544
                    Messages::resourceTypeNamedStreamWithSameNameAlreadyExists(
545
                        $name,
546
                        $this->name
547
                    )
548
                );
549
            }
550
        }
551
552
        $this->namedStreamsDeclaredOnThisType[$name] = $namedStream;
553
        // Set $this->allNamedStreams to null, the first call to getAllNamedStreams
554
        // will initialize $this->allNamedStreams, further call to
555
        // getAllNamedStreams will not reinitialize _allNamedStreams
556
        // so if addNamedStream is called after calling getAllNamedStreams then the
557
        // property just added will not be reflected in $this->allNamedStreams
558
        unset($this->allNamedStreams);
559
        $this->allNamedStreams = [];
560
    }
561
562
    /**
563
     * Get collection of ResourceStreamInfo describing the named streams belongs
564
     * to this resource type (excluding base class properties).
565
     *
566
     * @return ResourceStreamInfo[]
567
     */
568
    public function getNamedStreamsDeclaredOnThisType()
569
    {
570
        return $this->namedStreamsDeclaredOnThisType;
571
    }
572
573
    /**
574
     * Get collection of ResourceStreamInfo describing the named streams belongs
575
     * to this resource type including base class named streams.
576
     *
577
     * @return ResourceStreamInfo[]
578
     */
579
    public function getAllNamedStreams()
580
    {
581
        if (empty($this->allNamedStreams)) {
582
            if (null != $this->baseType) {
583
                $this->allNamedStreams = $this->baseType->getAllNamedStreams();
584
            }
585
586
            $this->allNamedStreams
587
                = array_merge(
588
                    $this->allNamedStreams,
589
                    $this->namedStreamsDeclaredOnThisType
590
                );
591
        }
592
593
        return $this->allNamedStreams;
594
    }
595
596
    /**
597
     * Try to get ResourceStreamInfo for a named stream defined for this
598
     * resource type excluding base class named streams.
599
     *
600
     * @param string $namedStreamName Name of the named stream to resolve
601
     *
602
     * @return ResourceStreamInfo|null
603
     */
604
    public function tryResolveNamedStreamDeclaredOnThisTypeByName($namedStreamName)
605
    {
606
        if (array_key_exists($namedStreamName, $this->namedStreamsDeclaredOnThisType)) {
607
            return $this->namedStreamsDeclaredOnThisType[$namedStreamName];
608
        }
609
        return null;
610
    }
611
612
    /**
613
     * Try to get ResourceStreamInfo for a named stream defined for this resource
614
     * type including base class named streams.
615
     *
616
     * @param string $namedStreamName Name of the named stream to resolve
617
     *
618
     * @return ResourceStreamInfo|null
619
     */
620
    public function tryResolveNamedStreamByName($namedStreamName)
621
    {
622
        if (array_key_exists($namedStreamName, $this->getAllNamedStreams())) {
623
            return $this->allNamedStreams[$namedStreamName];
624
        }
625
        return null;
626
    }
627
628
    /**
629
     * Check this resource type instance has named stream associated with it
630
     * Note: This is an internal method used by library. Devs don't use this.
631
     *
632
     * @return bool true if resource type instance has named stream else false
633
     */
634
    public function hasNamedStream()
635
    {
636
        // Note: Calling this method will initialize _allNamedStreams
637
        // and _hasNamedStreams flag to a boolean value
638
        // from null depending on the current state of _allNamedStreams
639
        // array, so method should be called only after adding all
640
        // named streams
641
        if (is_null($this->hasNamedStreams)) {
642
            $this->getAllNamedStreams();
643
            $this->hasNamedStreams = !empty($this->allNamedStreams);
644
        }
645
646
        return $this->hasNamedStreams;
647
    }
648
649
    /**
650
     * Check this resource type instance has bag property associated with it
651
     * Note: This is an internal method used by library. Devs don't use this.
652
     *
653
     * @param array &$arrayToDetectLoopInComplexType array for detecting loop
654
     *
655
     * @return bool|null true if resource type instance has bag property else false
656
     */
657
    public function hasBagProperty(&$arrayToDetectLoopInComplexType)
658
    {
659
        // Note: Calling this method will initialize _bagProperties
660
        // and _hasBagProperty flag to a boolean value
661
        // from null depending on the current state of
662
        // _propertiesDeclaredOnThisType array, so method
663
        // should be called only after adding all properties
664
        if (!is_null($this->hasBagProperty)) {
665
            return $this->hasBagProperty;
666
        }
667
668
        if (null != $this->baseType && $this->baseType->hasBagProperty($arrayToDetectLoopInComplexType)) {
669
            $this->hasBagProperty = true;
670
        } else {
671
            foreach ($this->propertiesDeclaredOnThisType as $resourceProperty) {
672
                $hasBagInComplex = false;
673
                if ($resourceProperty->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) {
674
                    //We can say current ResouceType ("this")
675
                    //is contains a bag property if:
676
                    //1. It contain a property of kind bag.
677
                    //2. It contains a normal complex property
678
                    //with a sub property of kind bag.
679
                    //The second case can be further expanded, i.e.
680
                    //if the normal complex property
681
                    //has a normal complex sub property with a
682
                    //sub property of kind bag.
683
                    //So for complex type we recursively call this
684
                    //function to check for bag.
685
                    //Shown below how looping can happen in complex type:
686
                    //Customer ResourceType (id1)
687
                    //{
688
                    //  ....
689
                    //  Address: Address ResourceType (id2)
690
                    //  {
691
                    //    .....
692
                    //    AltAddress: Address ResourceType (id2)
693
                    //    {
694
                    //      ...
695
                    //    }
696
                    //  }
697
                    //}
698
699
                    //Here the resource type of Customer::Address and
700
                    //Customer::Address::AltAddress
701
                    //are same, this is a loop, we need to detect
702
                    //this and avoid infinite recursive loop.
703
704
                    $count = count($arrayToDetectLoopInComplexType);
705
                    $foundLoop = false;
706
                    for ($i = 0; $i < $count; ++$i) {
707
                        if ($arrayToDetectLoopInComplexType[$i] === $resourceProperty->getResourceType()) {
708
                            $foundLoop = true;
709
                            break;
710
                        }
711
                    }
712
713
                    if (!$foundLoop) {
714
                        $arrayToDetectLoopInComplexType[$count] = $resourceProperty->getResourceType();
715
                        $hasBagInComplex = $resourceProperty
716
                            ->getResourceType()
717
                            ->hasBagProperty($arrayToDetectLoopInComplexType);
718
                        unset($arrayToDetectLoopInComplexType[$count]);
719
                    }
720
                }
721
722
                if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG) || $hasBagInComplex) {
723
                    $this->hasBagProperty = true;
724
                    break;
725
                }
726
            }
727
        }
728
729
        return $this->hasBagProperty;
730
    }
731
732
    /**
733
     * Validate the type.
734
     *
735
     *
736
     * @throws InvalidOperationException
737
     */
738
    public function validateType()
739
    {
740
        $keyProperties = $this->getKeyProperties();
741
        if (($this->resourceTypeKind == ResourceTypeKind::ENTITY) && empty($keyProperties)) {
742
            throw new InvalidOperationException(
743
                Messages::resourceTypeMissingKeyPropertiesForEntity(
744
                    $this->getFullName()
745
                )
746
            );
747
        }
748
    }
749
750
    /**
751
     * To check the type described by this resource type is assignable from
752
     * a type described by another resource type. Or this type is a sub-type
753
     * of (derived from the) given resource type.
754
     *
755
     * @param ResourceType $resourceType Another resource type
756
     *
757
     * @return bool
758
     */
759
    public function isAssignableFrom(ResourceType $resourceType)
760
    {
761
        $base = $this;
762
        while (null != $base) {
763
            if ($resourceType == $base) {
764
                return true;
765
            }
766
767
            $base = $base->baseType;
768
        }
769
770
        return false;
771
    }
772
773
    /**
774
     * Get predefined ResourceType for a primitive type.
775
     *
776
     * @param EdmPrimitiveType $typeCode Typecode of primitive type
777
     *
778
     * @throws InvalidArgumentException
779
     *
780
     * @return ResourceType
781
     */
782
    public static function getPrimitiveResourceType($typeCode)
783
    {
784
        switch ($typeCode) {
785
            case EdmPrimitiveType::BINARY:
786
                return new ResourcePrimitiveType(new Binary());
787
            case EdmPrimitiveType::BOOLEAN:
788
                return new ResourcePrimitiveType(new Boolean());
789
            case EdmPrimitiveType::BYTE:
790
                return new ResourcePrimitiveType(new Byte());
791
            case EdmPrimitiveType::DATETIME:
792
                return new ResourcePrimitiveType(new DateTime());
793
            case EdmPrimitiveType::DECIMAL:
794
                return new ResourcePrimitiveType(new Decimal());
795
            case EdmPrimitiveType::DOUBLE:
796
                return new ResourcePrimitiveType(new Double());
797
            case EdmPrimitiveType::GUID:
798
                return new ResourcePrimitiveType(new Guid());
799
            case EdmPrimitiveType::INT16:
800
                return new ResourcePrimitiveType(new Int16());
801
            case EdmPrimitiveType::INT32:
802
                return new ResourcePrimitiveType(new Int32());
803
            case EdmPrimitiveType::INT64:
804
                return new ResourcePrimitiveType(new Int64());
805
            case EdmPrimitiveType::SBYTE:
806
                return new ResourcePrimitiveType(new SByte());
807
            case EdmPrimitiveType::SINGLE:
808
                return new ResourcePrimitiveType(new Single());
809
            case EdmPrimitiveType::STRING:
810
                return new ResourcePrimitiveType(new StringType());
811
            default:
812
                throw new \InvalidArgumentException(
813
                    Messages::commonNotValidPrimitiveEDMType(
814
                        '$typeCode',
815
                        'getPrimitiveResourceType'
816
                    )
817
                );
818
        }
819
    }
820
821
    /**
822
     * @param string $property
823
     */
824
    public function setPropertyValue($entity, $property, $value)
825
    {
826
        \POData\Common\ReflectionHandler::setProperty($entity, $property, $value);
827
828
        return $this;
829
    }
830
831
    public function getPropertyValue($entity, $property)
832
    {
833
        return \POData\Common\ReflectionHandler::getProperty($entity, $property);
834
    }
835
836
    public function __sleep()
837
    {
838
        if (null == $this->type || $this->type instanceof \POData\Providers\Metadata\Type\IType) {
839
            return array_keys(get_object_vars($this));
840
        }
841
        $this->type = $this->type->name;
842
        $result = array_keys(get_object_vars($this));
843
844
        return $result;
845
    }
846
847
    public function __wakeup()
848
    {
849
        if (is_string($this->type)) {
850
            $this->type = new \ReflectionClass($this->type);
851
        }
852
853
        assert(
854
            $this->type instanceof \ReflectionClass || $this->type instanceof IType,
855
            '_type neither instance of reflection class nor IType'
856
        );
857
    }
858
}
859