Test Setup Failed
Push — master ( cd6ee4...9894d0 )
by Alex
53s
created

ProvidersWrapper   C

Complexity

Total Complexity 64

Size/Duplication

Total Lines 823
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 10

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 64
c 4
b 0
f 0
lcom 2
cbo 10
dl 0
loc 823
rs 5

33 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A getProviderWrapper() 0 5 1
A getContainerName() 0 12 2
A getContainerNamespace() 0 12 2
A getConfiguration() 0 4 1
A getResourceSets() 0 20 4
A _validateResourceSetAndGetWrapper() 0 14 3
A validateResourceType() 0 12 2
A getTypes() 0 18 3
A getSingletons() 0 5 2
A resolveResourceSet() 0 13 3
A resolveResourceType() 0 9 2
A resolveSingleton() 0 8 2
A getDerivedTypes() 0 15 3
A hasDerivedTypes() 0 6 1
B getResourceProperties() 0 31 6
B getResourceSetWrapperForNavigationProperty() 0 24 2
B getResourceAssociationSet() 0 66 7
A getResourceTypeWherePropertyIsDeclared() 0 12 3
A validateResourceSetAndGetWrapper() 0 4 1
A getEdmSchemaVersion() 0 5 1
A getExpressionProvider() 0 4 1
A handlesOrderedPaging() 0 4 1
A getResourceSet() 0 19 1
A getResourceFromResourceSet() 0 4 1
A putResource() 0 11 1
B getRelatedResourceSet() 0 25 1
A getResourceFromRelatedResourceSet() 0 15 1
A getRelatedResourceReference() 0 13 1
A updateResource() 0 15 1
A deleteResource() 0 9 1
A createResourceforResourceSet() 0 11 1
A getMetadataXML() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like ProvidersWrapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ProvidersWrapper, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace POData\Providers;
4
5
use POData\Common\InvalidOperationException;
6
use POData\Common\Messages;
7
use POData\Common\ODataException;
8
use POData\Configuration\IServiceConfiguration;
9
use POData\Providers\Expression\IExpressionProvider;
10
use POData\Providers\Metadata\EdmSchemaVersion;
11
use POData\Providers\Metadata\IMetadataProvider;
12
use POData\Providers\Metadata\ResourceAssociationSet;
13
use POData\Providers\Metadata\ResourceEntityType;
14
use POData\Providers\Metadata\ResourceProperty;
15
use POData\Providers\Metadata\ResourceSet;
16
use POData\Providers\Metadata\ResourceSetWrapper;
17
use POData\Providers\Metadata\ResourceType;
18
use POData\Providers\Metadata\ResourceTypeKind;
19
use POData\Providers\Query\IQueryProvider;
20
use POData\Providers\Query\QueryResult;
21
use POData\Providers\Query\QueryType;
22
use POData\UriProcessor\QueryProcessor\ExpressionParser\FilterInfo;
23
use POData\UriProcessor\QueryProcessor\OrderByParser\InternalOrderByInfo;
24
use POData\UriProcessor\QueryProcessor\SkipTokenParser\InternalSkipTokenInfo;
25
use POData\UriProcessor\QueryProcessor\SkipTokenParser\SkipTokenInfo;
26
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\KeyDescriptor;
27
28
/**
29
 * Class ProvidersWrapper.
30
 *
31
 * A wrapper class over IMetadataProvider and IQueryProvider implementations, All calls to implementation of methods
32
 * of these interfaces should go through this wrapper class so that wrapper methods of this class can perform validation
33
 */
34
class ProvidersWrapper
35
{
36
    /**
37
     * Holds reference to IMetadataProvider implementation.
38
     *
39
     * @var IMetadataProvider
40
     */
41
    private $metaProvider;
42
43
    /**
44
     * Holds reference to IServiceConfiguration implementation.
45
     *
46
     * @var IServiceConfiguration
47
     */
48
    private $config;
49
50
    /*
51
     * Holds reference to ProvidersQueryWrapper implementation
52
     *
53
     * @var ProvidersQueryWrapper
54
     */
55
    private $providerWrapper;
56
57
    /**
58
     * Cache for ResourceProperties of a resource type that belongs to a
59
     * resource set. An entry (ResourceProperty collection) in this cache
60
     * contains only the visible properties of ResourceType.
61
     *
62
     * @var array(string, array(string, ResourceProperty))
63
     */
64
    private $propertyCache;
65
66
    /**
67
     * Cache for ResourceSetWrappers. If ResourceSet is invisible value will
68
     * be null.
69
     *
70
     * @var ResourceSetWrapper[] indexed by resource set name
71
     */
72
    private $setWrapperCache;
73
74
    /**
75
     * Cache for ResourceTypes.
76
     *
77
     * @var ResourceType[] indexed by resource type name
78
     */
79
    private $typeCache;
80
81
    /**
82
     * Cache for ResourceAssociationSet. If ResourceAssociationSet is invisible
83
     * value will be null.
84
     *
85
     * @var ResourceAssociationSet[] indexed by name
86
     */
87
    private $associationSetCache;
0 ignored issues
show
Unused Code introduced by
The property $associationSetCache is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
88
89
    /**
90
     * Creates a new instance of ProvidersWrapper.
91
     *
92
     * @param IMetadataProvider     $meta   Reference to IMetadataProvider implementation
93
     * @param IQueryProvider        $query  Reference to IQueryProvider implementation
94
     * @param IServiceConfiguration $config Reference to IServiceConfiguration implementation
95
     */
96
    public function __construct(IMetadataProvider $meta, IQueryProvider $query, IServiceConfiguration $config)
97
    {
98
        $this->metaProvider = $meta;
99
        $this->config = $config;
100
        $this->providerWrapper = new ProvidersQueryWrapper($query);
101
        $this->setWrapperCache = [];
102
        $this->typeCache = [];
103
        $this->propertyCache = [];
104
    }
105
106
    public function getProviderWrapper()
107
    {
108
        assert(null != $this->providerWrapper, "Provider wrapper must be set");
109
        return $this->providerWrapper;
110
    }
111
112
    //Wrappers for IMetadataProvider methods
113
114
    /**
115
     * To get the Container name for the data source,
116
     * Note: Wrapper for IMetadataProvider::getContainerName method
117
     * implementation.
118
     *
119
     * @throws ODataException Exception if implementation returns empty container name
120
     *
121
     * @return string that contains the name of the container
122
     */
123
    public function getContainerName()
124
    {
125
        $containerName = $this->metaProvider->getContainerName();
126
        if (empty($containerName)) {
127
            throw new ODataException(
128
                Messages::providersWrapperContainerNameMustNotBeNullOrEmpty(),
129
                500
130
            );
131
        }
132
133
        return $containerName;
134
    }
135
136
    /**
137
     * To get Namespace name for the data source,
138
     * Note: Wrapper for IMetadataProvider::getContainerNamespace method implementation.
139
     *
140
     * @throws ODataException Exception if implementation returns empty container namespace
141
     *
142
     * @return string that contains the namespace name
143
     */
144
    public function getContainerNamespace()
145
    {
146
        $containerNamespace = $this->metaProvider->getContainerNamespace();
147
        if (empty($containerNamespace)) {
148
            throw new ODataException(
149
                Messages::providersWrapperContainerNamespaceMustNotBeNullOrEmpty(),
150
                500
151
            );
152
        }
153
154
        return $containerNamespace;
155
    }
156
157
    /**
158
     * To get the data service configuration.
159
     *
160
     * @return IServiceConfiguration
161
     */
162
    public function getConfiguration()
163
    {
164
        return $this->config;
165
    }
166
167
    /**
168
     *  To get all entity set information,
169
     *  Note: Wrapper for IMetadataProvider::getResourceSets method implementation,
170
     *  This method returns array of ResourceSetWrapper instances but the corresponding IDSMP method
171
     *  returns array of ResourceSet instances.
172
     *
173
     *  @throws ODataException when two resource sets with the same name are encountered
174
     *
175
     *  @return ResourceSetWrapper[] The ResourceSetWrappers for the visible ResourceSets
176
     */
177
    public function getResourceSets()
178
    {
179
        $resourceSets = $this->metaProvider->getResourceSets();
180
        $resourceSetWrappers = [];
181
        $resourceSetNames = [];
182
        foreach ($resourceSets as $resourceSet) {
183
            $name = $resourceSet->getName();
184
            if (in_array($name, $resourceSetNames)) {
185
                throw new ODataException(Messages::providersWrapperEntitySetNameShouldBeUnique($name), 500);
186
            }
187
188
            $resourceSetNames[] = $name;
189
            $resourceSetWrapper = $this->_validateResourceSetAndGetWrapper($resourceSet);
190
            if (!is_null($resourceSetWrapper)) {
191
                $resourceSetWrappers[] = $resourceSetWrapper;
192
            }
193
        }
194
195
        return $resourceSetWrappers;
196
    }
197
198
    /**
199
     * This function perform the following operations
200
     *  (1) If the cache contain an entry [key, value] for the resourceset then
201
     *      return the entry-value
202
     *  (2) If the cache not contain an entry for the resourceset then validate
203
     *      the resourceset
204
     *            (a) If valid add entry as [resouceset_name, resourceSetWrapper]
205
     *            (b) if not valid add entry as [resouceset_name, null]
206
     *  Note: validating a resourceset means checking the resourceset is visible
207
     *  or not using configuration.
208
     *
209
     * @param ResourceSet $resourceSet The resourceset to validate and get the
210
     *                                 wrapper for
211
     *
212
     * @return ResourceSetWrapper|null Returns an instance if a resource set with the given name is visible
213
     */
214
    private function _validateResourceSetAndGetWrapper(ResourceSet $resourceSet)
215
    {
216
        $cacheKey = $resourceSet->getName();
217
        if (array_key_exists($cacheKey, $this->setWrapperCache)) {
218
            return $this->setWrapperCache[$cacheKey];
219
        }
220
221
        $this->validateResourceType($resourceSet->getResourceType());
222
        $wrapper = new ResourceSetWrapper($resourceSet, $this->config);
223
        $nuVal = $wrapper->isVisible() ? $wrapper : null;
224
        $this->setWrapperCache[$cacheKey] = $nuVal;
225
226
        return $this->setWrapperCache[$cacheKey];
227
    }
228
229
    /**
230
     * Validates the given instance of ResourceType.
231
     *
232
     * @param ResourceType $resourceType The ResourceType to validate
233
     *
234
     * @throws ODataException Exception if $resourceType is invalid
235
     *
236
     * @return ResourceType
237
     */
238
    private function validateResourceType(ResourceType $resourceType)
239
    {
240
        $cacheKey = $resourceType->getName();
241
        if (array_key_exists($cacheKey, $this->typeCache)) {
242
            return $this->typeCache[$cacheKey];
243
        }
244
245
        //TODO: Do validation if any for the ResourceType
246
        $this->typeCache[$cacheKey] = $resourceType;
247
248
        return $resourceType;
249
    }
250
251
    /**
252
     * To get all resource types in the data source,
253
     * Note: Wrapper for IMetadataProvider::getTypes method implementation.
254
     *
255
     * @return ResourceType[]
256
     */
257
    public function getTypes()
258
    {
259
        $resourceTypes = $this->metaProvider->getTypes();
260
        $resourceTypeNames = [];
261
        foreach ($resourceTypes as $resourceType) {
262
            if (in_array($resourceType->getName(), $resourceTypeNames)) {
263
                throw new ODataException(
264
                    Messages::providersWrapperEntityTypeNameShouldBeUnique($resourceType->getName()),
265
                    500
266
                );
267
            }
268
269
            $resourceTypeNames[] = $resourceType->getName();
270
            $this->validateResourceType($resourceType);
271
        }
272
273
        return $resourceTypes;
274
    }
275
276
    public function getSingletons()
277
    {
278
        $singletons = $this->metaProvider->getSingletons();
279
        return (null == $singletons) ? [] : $singletons;
280
    }
281
282
    /**
283
     * To get a resource set based on the specified resource set name which is
284
     * visible,
285
     * Note: Wrapper for IMetadataProvider::resolveResourceSet method
286
     * implementation.
287
     *
288
     * @param string $name Name of the resource set
289
     *
290
     * @return ResourceSetWrapper|null Returns resource set with the given name if found,
291
     *                                 NULL if resource set is set to invisible or not found
292
     */
293
    public function resolveResourceSet($name)
294
    {
295
        if (array_key_exists($name, $this->setWrapperCache)) {
296
            return $this->setWrapperCache[$name];
297
        }
298
299
        $resourceSet = $this->metaProvider->resolveResourceSet($name);
300
        if (is_null($resourceSet)) {
301
            return null;
302
        }
303
304
        return $this->_validateResourceSetAndGetWrapper($resourceSet);
305
    }
306
307
    /**
308
     * To get a resource type based on the resource set name,
309
     * Note: Wrapper for IMetadataProvider::resolveResourceType
310
     * method implementation.
311
     *
312
     * @param string $name Name of the resource set
313
     *
314
     * @throws ODataException If the ResourceType is invalid
315
     *
316
     * @return ResourceType|null resource type with the given resource set name if found else NULL
317
     */
318
    public function resolveResourceType($name)
319
    {
320
        $resourceType = $this->metaProvider->resolveResourceType($name);
321
        if (is_null($resourceType)) {
322
            return null;
323
        }
324
325
        return $this->validateResourceType($resourceType);
326
    }
327
328
329
    public function resolveSingleton($name)
330
    {
331
        $singletons = $this->metaProvider->getSingletons();
332
        if (array_key_exists($name, $singletons)) {
333
            return $singletons[$name];
334
        }
335
        return null;
336
    }
337
338
    /**
339
     * The method must return a collection of all the types derived from
340
     * $resourceType The collection returned should NOT include the type
341
     * passed in as a parameter
342
     * Note: Wrapper for IMetadataProvider::getDerivedTypes
343
     * method implementation.
344
     *
345
     * @param ResourceType $resourceType Resource to get derived resource types from
346
     *
347
     * @throws InvalidOperationException when the meat provider doesn't return an array
348
     *
349
     * @return ResourceType[]
350
     */
351
    public function getDerivedTypes(ResourceType $resourceType)
352
    {
353
        $derivedTypes = $this->metaProvider->getDerivedTypes($resourceType);
0 ignored issues
show
Compatibility introduced by
$resourceType of type object<POData\Providers\Metadata\ResourceType> is not a sub-type of object<POData\Providers\...ata\ResourceEntityType>. It seems like you assume a child class of the class POData\Providers\Metadata\ResourceType to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
354
        if (!is_array($derivedTypes)) {
355
            throw new InvalidOperationException(
356
                Messages::metadataAssociationTypeSetInvalidGetDerivedTypesReturnType($resourceType->getName())
357
            );
358
        }
359
360
        foreach ($derivedTypes as $derivedType) {
361
            $this->validateResourceType($derivedType);
362
        }
363
364
        return $derivedTypes;
365
    }
366
367
    /**
368
     * Returns true if $resourceType represents an Entity Type which has derived
369
     * Entity Types, else false.
370
     * Note: Wrapper for IMetadataProvider::hasDerivedTypes method
371
     * implementation.
372
     *
373
     * @param ResourceType $resourceType Resource to check for derived resource
374
     *                                   types
375
     *
376
     * @throws ODataException If the ResourceType is invalid
377
     *
378
     * @return bool
379
     */
380
    public function hasDerivedTypes(ResourceType $resourceType)
381
    {
382
        $this->validateResourceType($resourceType);
383
384
        return $this->metaProvider->hasDerivedTypes($resourceType);
0 ignored issues
show
Compatibility introduced by
$resourceType of type object<POData\Providers\Metadata\ResourceType> is not a sub-type of object<POData\Providers\...ata\ResourceEntityType>. It seems like you assume a child class of the class POData\Providers\Metadata\ResourceType to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
385
    }
386
387
    /**
388
     * Gets the visible resource properties for the given resource type from the given resource set wrapper.
389
     *
390
     * @param ResourceSetWrapper $setWrapper Resource set wrapper in question
391
     * @param ResourceType $resourceType Resource type in question
392
     *
393
     * @return ResourceProperty[] Collection of visible resource properties from the given resource set wrapper
394
     *                            and resource type
395
     */
396
    public function getResourceProperties(ResourceSetWrapper $setWrapper, ResourceType $resourceType)
397
    {
398
        if ($resourceType->getResourceTypeKind() != ResourceTypeKind::ENTITY) {
399
            //Complex resource type
400
            return $resourceType->getAllProperties();
401
        }
402
        //TODO: move this to doctrine annotations
403
        $cacheKey = $setWrapper->getName() . '_' . $resourceType->getFullName();
404
        if (!array_key_exists($cacheKey, $this->propertyCache)) {
405
            //Fill the cache
406
            $this->propertyCache[$cacheKey] = [];
407
            foreach ($resourceType->getAllProperties() as $resourceProperty) {
408
                //Check whether this is a visible navigation property
409
                //TODO: is this broken?? see #87
410
                if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY
411
                    && !is_null($this->getResourceSetWrapperForNavigationProperty(
412
                        $setWrapper,
413
                        $resourceType,
0 ignored issues
show
Compatibility introduced by
$resourceType of type object<POData\Providers\Metadata\ResourceType> is not a sub-type of object<POData\Providers\...ata\ResourceEntityType>. It seems like you assume a child class of the class POData\Providers\Metadata\ResourceType to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
414
                        $resourceProperty
415
                    ))
416
                ) {
417
                    $this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty;
418
                } else {
419
                    //primitive, bag or complex property
420
                    $this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty;
421
                }
422
            }
423
        }
424
425
        return $this->propertyCache[$cacheKey];
426
    }
427
428
    /**
429
     * Gets the target resource set wrapper for the given navigation property,
430
     * source resource set wrapper and the source resource type.
431
     *
432
     * @param ResourceSetWrapper $resourceSetWrapper Source resource set
433
     * @param ResourceEntityType $resourceType Source resource type
434
     * @param ResourceProperty   $navigationResourceProperty Navigation property
435
     *
436
     * @return ResourceSetWrapper|null Returns instance of ResourceSetWrapper
437
     *                                 (describes the entity set and associated configuration) for the
438
     *                                 given navigation property. returns NULL if resourceset for the
439
     *                                 navigation property is invisible or if metadata provider returns
440
     *                                 null resource association set
441
     */
442
    public function getResourceSetWrapperForNavigationProperty(
443
        ResourceSetWrapper $resourceSetWrapper,
444
        ResourceEntityType $resourceType,
445
        ResourceProperty $navigationResourceProperty
446
    ) {
447
        $associationSet = $this->getResourceAssociationSet(
448
            $resourceSetWrapper,
449
            $resourceType,
450
            $navigationResourceProperty
451
        );
452
453
        if (!is_null($associationSet)) {
454
            $relatedAssociationSetEnd = $associationSet->getRelatedResourceAssociationSetEnd(
455
                $resourceSetWrapper->getResourceSet(),
456
                $resourceType,
457
                $navigationResourceProperty
458
            );
459
460
            return $this->_validateResourceSetAndGetWrapper(
461
                $relatedAssociationSetEnd->getResourceSet()
462
            );
463
        }
464
        return null;
465
    }
466
467
    /**
468
     * Gets the ResourceAssociationSet instance for the given source association end,
469
     * Note: Wrapper for IMetadataProvider::getResourceAssociationSet
470
     * method implementation.
471
     *
472
     * @param ResourceSet           $set      Resource set of the source association end
473
     * @param ResourceEntityType    $type     Resource type of the source association end
474
     * @param ResourceProperty      $property Resource property of the source association end
475
     *
476
     * @return ResourceAssociationSet|null Returns ResourceAssociationSet for the source
477
     *                                     association end, NULL if no such
478
     *                                     association end or resource set in the
479
     *                                     other end of the association is invisible
480
     */
481
    public function getResourceAssociationSet(
482
        ResourceSet $set,
483
        ResourceEntityType $type,
484
        ResourceProperty $property
485
    ) {
486
        $type = $this->getResourceTypeWherePropertyIsDeclared($type, $property);
487
        // usage below requires $type to not be null - so kaboom as early as possible
488
        assert(null != $type, 'Resource type obtained from property must not be null.');
489
490
        $associationSet = $this->metaProvider->getResourceAssociationSet(
491
            $set,
492
            $type,
0 ignored issues
show
Compatibility introduced by
$type of type object<POData\Providers\Metadata\ResourceType> is not a sub-type of object<POData\Providers\...ata\ResourceEntityType>. It seems like you assume a child class of the class POData\Providers\Metadata\ResourceType to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
493
            $property
494
        );
495
        assert(
496
            null == $associationSet || $associationSet instanceof ResourceAssociationSet,
497
            "Retrieved resource assocation must be either null or an instance of ResourceAssociationSet"
498
        );
499
500
        if (!is_null($associationSet)) {
501
            $thisAssociationSetEnd = $associationSet->getResourceAssociationSetEnd(
502
                $set,
503
                $type,
0 ignored issues
show
Compatibility introduced by
$type of type object<POData\Providers\Metadata\ResourceType> is not a sub-type of object<POData\Providers\...ata\ResourceEntityType>. It seems like you assume a child class of the class POData\Providers\Metadata\ResourceType to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
504
                $property
505
            );
506
507
            $relatedAssociationSetEnd = $associationSet->getRelatedResourceAssociationSetEnd(
508
                $set,
509
                $type,
0 ignored issues
show
Compatibility introduced by
$type of type object<POData\Providers\Metadata\ResourceType> is not a sub-type of object<POData\Providers\...ata\ResourceEntityType>. It seems like you assume a child class of the class POData\Providers\Metadata\ResourceType to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
510
                $property
511
            );
512
513
            //If either $thisAssociationSetEnd and/or $relatedAssociationSetEnd
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
514
            //is null means the associationset we got from the IDSMP::getResourceAssociationSet is invalid.
515
516
            //Return null, if either AssociationSet's End1 or End2's resourceset name
517
            //doesn't match the name of resource set wrapper (param1) and resource type is not assignable
518
            //from given resource type (param2)
519
            if (is_null($thisAssociationSetEnd) || is_null($relatedAssociationSetEnd)) {
520
                throw new ODataException(
521
                    Messages::providersWrapperIDSMPGetResourceSetReturnsInvalidResourceSet(
522
                        $set->getName(),
523
                        $type->getFullName(),
524
                        $property->getName()
525
                    ),
526
                    500
527
                );
528
            }
529
530
            $relatedResourceSetWrapper = $this->_validateResourceSetAndGetWrapper(
531
                $relatedAssociationSetEnd->getResourceSet()
532
            );
533
            if ($relatedResourceSetWrapper === null) {
534
                $associationSet = null;
535
            } else {
536
                $this->validateResourceType($thisAssociationSetEnd->getResourceType());
537
                $this->validateResourceType($relatedAssociationSetEnd->getResourceType());
538
            }
539
        }
540
        assert(
541
            null == $associationSet || $associationSet instanceof ResourceAssociationSet,
542
            "Retrieved resource assocation must be either null or an instance of ResourceAssociationSet"
543
        );
544
545
        return $associationSet;
546
    }
547
548
    /**
549
     * Gets the resource type on which the resource property is declared on,
550
     * If property is not declared in the given resource type, then this
551
     * function drill down to the inheritance hierarchy of the given resource
552
     * type to find out the base class in which the property is declared.
553
     *
554
     * @param ResourceType     $type     The resource type to start looking
555
     * @param ResourceProperty $property The resource property in question
556
     *
557
     * @return ResourceType|null Returns reference to the ResourceType on which
558
     *                           the $property is declared, NULL if
559
     *                           $property is not declared anywhere
560
     *                           in the inheritance hierarchy
561
     */
562
    private function getResourceTypeWherePropertyIsDeclared(ResourceType $type, ResourceProperty $property)
563
    {
564
        while (null !== $type) {
565
            if (null !== $type->resolvePropertyDeclaredOnThisType($property->getName())) {
566
                break;
567
            }
568
569
            $type = $type->getBaseType();
570
        }
571
572
        return $type;
573
    }
574
575
    /**
576
     * Wrapper function over _validateResourceSetAndGetWrapper function.
577
     *
578
     * @param ResourceSet $resourceSet see the comments of _validateResourceSetAndGetWrapper
579
     *
580
     * @return ResourceSetWrapper|null see the comments of _validateResourceSetAndGetWrapper
581
     */
582
    public function validateResourceSetAndGetWrapper(ResourceSet $resourceSet)
583
    {
584
        return $this->_validateResourceSetAndGetWrapper($resourceSet);
585
    }
586
587
    /**
588
     * Gets the Edm Schema version compliance to the metadata.
589
     *
590
     * @return EdmSchemaVersion
591
     */
592
    public function getEdmSchemaVersion()
593
    {
594
        //The minimal schema version for custom provider is 1.1
595
        return EdmSchemaVersion::VERSION_1_DOT_1;
596
    }
597
598
    /**
599
     * Gets the underlying custom expression provider, the end developer is
600
     * responsible for implementing IExpressionProvider if he choose for.
601
     *
602
     * @return IExpressionProvider Instance of IExpressionProvider implementation
603
     */
604
    public function getExpressionProvider()
605
    {
606
        return $this->getProviderWrapper()->getExpressionProvider();
607
    }
608
609
    /**
610
     * Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters
611
     * If the query provider can not handle ordered paging, it must return the entire result set and POData will
612
     * perform the ordering and paging.
613
     *
614
     * @return bool True if the query provider can handle ordered paging, false if POData should perform the paging
615
     */
616
    public function handlesOrderedPaging()
617
    {
618
        return $this->getProviderWrapper()->handlesOrderedPaging();
619
    }
620
621
    /**
622
     * Gets collection of entities belongs to an entity set.
623
     *
624
     * @param QueryType             $queryType   Indicates if this is a query for a count, entities, or entities with a
625
     *                                           count
626
     * @param ResourceSet           $resourceSet The entity set containing the entities that need to be fetched
627
     * @param FilterInfo            $filterInfo  Represents the $filter parameter of the OData query.
628
     *                                           NULL if no $filter specified
629
     * @param InternalOrderByInfo   $orderBy     The orderBy information
630
     * @param int                   $top         The top count
631
     * @param int                   $skip        The skip count
632
     * @param InternalSkipTokenInfo $skipToken   The skip token
633
     *
634
     * @return QueryResult
635
     */
636
    public function getResourceSet(
637
        QueryType $queryType,
638
        ResourceSet $resourceSet,
639
        FilterInfo $filterInfo = null,
640
        InternalOrderByInfo $orderBy = null,
641
        $top = null,
642
        $skip = null,
643
        SkipTokenInfo $skipToken = null
644
    ) {
645
        return $this->getProviderWrapper()->getResourceSet(
646
            $queryType,
647
            $resourceSet,
648
            $filterInfo,
649
            $orderBy,
650
            $top,
651
            $skip,
652
            $skipToken
653
        );
654
    }
655
656
    /**
657
     * Gets an entity instance from an entity set identified by a key.
658
     *
659
     * @param ResourceSet   $resourceSet   The entity set containing the entity to fetch
660
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
661
     *
662
     * @return object|null Returns entity instance if found else null
663
     */
664
    public function getResourceFromResourceSet(ResourceSet $resourceSet, KeyDescriptor $keyDescriptor)
665
    {
666
        return $this->getProviderWrapper()->getResourceFromResourceSet($resourceSet, $keyDescriptor);
667
    }
668
669
    /**
670
     * Puts an entity instance to entity set identified by a key.
671
     *
672
     * @param ResourceSet   $resourceSet   The entity set containing the entity to update
673
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to update
674
     *
675
     * @return bool|null Returns result of executiong query
676
     */
677
    public function putResource(
678
        ResourceSet $resourceSet,
679
        KeyDescriptor $keyDescriptor,
680
        $data
681
    ) {
682
        return $this->getProviderWrapper()->putResource(
683
            $resourceSet,
684
            $keyDescriptor,
685
            $data
686
        );
687
    }
688
689
    /**
690
     * Get related resource set for a resource.
691
     *
692
     * @param QueryType             $queryType         Indicates if this is a query for a count, entities, or entities
693
     *                                                 with a count
694
     * @param ResourceSet           $sourceResourceSet The entity set containing the source entity
695
     * @param object                $sourceEntity      The source entity instance
696
     * @param ResourceSet           $targetResourceSet The resource set containing the target of the navigation property
697
     * @param ResourceProperty      $targetProperty    The navigation property to retrieve
698
     * @param FilterInfo|null       $filterInfo        Represents the $filter parameter of the OData query.
699
     *                                                 NULL if no $filter specified
700
     * @param mixed                 $orderBy           sorted order if we want to get the data in some specific order
701
     * @param int                   $top                  number of records which need to be retrieved
702
     * @param int                   $skip                 number of records which need to be skipped
703
     * @param SkipTokenInfo|null    $skipToken            value indicating what records to skip
704
     *
705
     * @throws ODataException
706
     *
707
     * @return QueryResult
708
     */
709
    public function getRelatedResourceSet(
710
        QueryType $queryType,
711
        ResourceSet $sourceResourceSet,
712
        $sourceEntity,
713
        ResourceSet $targetResourceSet,
714
        ResourceProperty $targetProperty,
715
        $filterInfo,
716
        $orderBy,
717
        $top,
718
        $skip,
719
        SkipTokenInfo $skipToken = null
720
    ) {
721
        return $this->getProviderWrapper()->getRelatedResourceSet(
722
            $queryType,
723
            $sourceResourceSet,
724
            $sourceEntity,
725
            $targetResourceSet,
726
            $targetProperty,
727
            $filterInfo,
0 ignored issues
show
Bug introduced by
It seems like $filterInfo defined by parameter $filterInfo on line 715 can be null; however, POData\Providers\Provide...getRelatedResourceSet() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
728
            $orderBy,
729
            $top,
730
            $skip,
731
            $skipToken
732
        );
733
    }
734
735
    /**
736
     * Gets a related entity instance from an entity set identified by a key.
737
     *
738
     * @param ResourceSet      $sourceResourceSet The entity set related to the entity to be fetched
739
     * @param object           $sourceEntity      The related entity instance
740
     * @param ResourceSet      $targetResourceSet The entity set from which entity needs to be fetched
741
     * @param ResourceProperty $targetProperty    The metadata of the target property
742
     * @param KeyDescriptor    $keyDescriptor     The key to identify the entity to be fetched
743
     *
744
     * @return object|null Returns entity instance if found else null
745
     */
746
    public function getResourceFromRelatedResourceSet(
747
        ResourceSet $sourceResourceSet,
748
        $sourceEntity,
749
        ResourceSet $targetResourceSet,
750
        ResourceProperty $targetProperty,
751
        KeyDescriptor $keyDescriptor
752
    ) {
753
        return $this->getProviderWrapper()->getResourceFromRelatedResourceSet(
754
            $sourceResourceSet,
755
            $sourceEntity,
756
            $targetResourceSet,
757
            $targetProperty,
758
            $keyDescriptor
759
        );
760
    }
761
762
    /**
763
     * Get related resource for a resource.
764
     *
765
     * @param ResourceSet      $sourceResourceSet The source resource set
766
     * @param object           $sourceEntity      The source resource
767
     * @param ResourceSet      $targetResourceSet The resource set of the navigation
768
     *                                            property
769
     * @param ResourceProperty $targetProperty    The navigation property to be
770
     *                                            retrieved
771
     *
772
     * @return object|null The related resource if exists else null
773
     */
774
    public function getRelatedResourceReference(
775
        ResourceSet $sourceResourceSet,
776
        $sourceEntity,
777
        ResourceSet $targetResourceSet,
778
        ResourceProperty $targetProperty
779
    ) {
780
        return $this->getProviderWrapper()->getRelatedResourceReference(
781
            $sourceResourceSet,
782
            $sourceEntity,
783
            $targetResourceSet,
784
            $targetProperty
785
        );
786
    }
787
788
    /**
789
     * Updates a resource.
790
     *
791
     * @param ResourceSet   $sourceResourceSet    The entity set containing the source entity
792
     * @param object        $sourceEntityInstance The source entity instance
793
     * @param KeyDescriptor $keyDescriptor        The key identifying the entity to fetch
794
     * @param object        $data                 The New data for the entity instance.
795
     * @param bool          $shouldUpdate         Should undefined values be updated or reset to default
796
     *
797
     * @return object|null The new resource value if it is assignable or throw exception for null.
798
     */
799
    public function updateResource(
800
        ResourceSet $sourceResourceSet,
801
        $sourceEntityInstance,
802
        KeyDescriptor $keyDescriptor,
803
        $data,
804
        $shouldUpdate = false
805
    ) {
806
        return $this->getProviderWrapper()->updateResource(
807
            $sourceResourceSet,
808
            $sourceEntityInstance,
809
            $keyDescriptor,
810
            $data,
811
            $shouldUpdate
812
        );
813
    }
814
815
    /**
816
     * Delete resource from a resource set.
817
     *
818
     * @param ResourceSet $sourceResourceSet
819
     * @param object      $sourceEntityInstance
820
     *
821
     * return bool true if resources sucessfully deteled, otherwise false.
822
     */
823
    public function deleteResource(
824
        ResourceSet $sourceResourceSet,
825
        $sourceEntityInstance
826
    ) {
827
        return $this->getProviderWrapper()->deleteResource(
828
            $sourceResourceSet,
829
            $sourceEntityInstance
830
        );
831
    }
832
833
    /**
834
     * @param ResourceSet $resourceSet          The entity set containing the entity to fetch
835
     * @param object      $sourceEntityInstance The source entity instance
836
     * @param object      $data                 The New data for the entity instance.
837
     *
838
     * returns object|null returns the newly created model if sucessful or null if model creation failed.
839
     */
840
    public function createResourceforResourceSet(
841
        ResourceSet $resourceSet,
842
        $sourceEntityInstance,
843
        $data
844
    ) {
845
        return $this->getProviderWrapper()->createResourceforResourceSet(
846
            $resourceSet,
847
            $sourceEntityInstance,
848
            $data
849
        );
850
    }
851
852
    public function getMetadataXML()
853
    {
854
        return $this->metaProvider->getXML();
855
    }
856
}
857