Test Setup Failed
Push — master ( 2bb3c0...689644 )
by Alex
04:15
created

ProvidersWrapper::hasDerivedTypes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
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\ResourcePathProcessor\SegmentParser\KeyDescriptor;
26
27
/**
28
 * Class ProvidersWrapper.
29
 *
30
 * A wrapper class over IMetadataProvider and IQueryProvider implementations, All calls to implementation of methods
31
 * of these interfaces should go through this wrapper class so that wrapper methods of this class can perform validation
32
 */
33
class ProvidersWrapper
34
{
35
    /**
36
     * Holds reference to IMetadataProvider implementation.
37
     *
38
     * @var IMetadataProvider
39
     */
40
    private $metaProvider;
41
42
    /**
43
     * Holds reference to IServiceConfiguration implementation.
44
     *
45
     * @var IServiceConfiguration
46
     */
47
    private $config;
48
49
    /*
50
     * Holds reference to ProvidersQueryWrapper implementation
51
     *
52
     * @var ProvidersQueryWrapper
53
     */
54
    private $providerWrapper;
55
56
    /**
57
     * Cache for ResourceProperties of a resource type that belongs to a
58
     * resource set. An entry (ResourceProperty collection) in this cache
59
     * contains only the visible properties of ResourceType.
60
     *
61
     * @var array(string, array(string, ResourceProperty))
62
     */
63
    private $propertyCache;
64
65
    /**
66
     * Cache for ResourceSetWrappers. If ResourceSet is invisible value will
67
     * be null.
68
     *
69
     * @var ResourceSetWrapper[] indexed by resource set name
70
     */
71
    private $setWrapperCache;
72
73
    /**
74
     * Cache for ResourceTypes.
75
     *
76
     * @var ResourceType[] indexed by resource type name
77
     */
78
    private $typeCache;
79
80
    /**
81
     * Cache for ResourceAssociationSet. If ResourceAssociationSet is invisible
82
     * value will be null.
83
     *
84
     * @var ResourceAssociationSet[] indexed by name
85
     */
86
    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...
87
88
    /**
89
     * Creates a new instance of ProvidersWrapper.
90
     *
91
     * @param IMetadataProvider     $meta   Reference to IMetadataProvider implementation
92
     * @param IQueryProvider        $query  Reference to IQueryProvider implementation
93
     * @param IServiceConfiguration $config Reference to IServiceConfiguration implementation
94
     */
95
    public function __construct(IMetadataProvider $meta, IQueryProvider $query, IServiceConfiguration $config)
96
    {
97
        $this->metaProvider = $meta;
98
        $this->config = $config;
99
        $this->providerWrapper = new ProvidersQueryWrapper($query);
100
        $this->setWrapperCache = [];
101
        $this->typeCache = [];
102
        $this->propertyCache = [];
103
    }
104
105
    //Wrappers for IMetadataProvider methods
106
107
    /**
108
     * To get the Container name for the data source,
109
     * Note: Wrapper for IMetadataProvider::getContainerName method
110
     * implementation.
111
     *
112
     * @throws ODataException Exception if implementation returns empty container name
113
     *
114
     * @return string that contains the name of the container
115
     */
116
    public function getContainerName()
117
    {
118
        $containerName = $this->metaProvider->getContainerName();
119
        if (empty($containerName)) {
120
            throw new ODataException(
121
                Messages::providersWrapperContainerNameMustNotBeNullOrEmpty(),
122
                500
123
            );
124
        }
125
126
        return $containerName;
127
    }
128
129
    /**
130
     * To get Namespace name for the data source,
131
     * Note: Wrapper for IMetadataProvider::getContainerNamespace method implementation.
132
     *
133
     * @throws ODataException Exception if implementation returns empty container namespace
134
     *
135
     * @return string that contains the namespace name
136
     */
137
    public function getContainerNamespace()
138
    {
139
        $containerNamespace = $this->metaProvider->getContainerNamespace();
140
        if (empty($containerNamespace)) {
141
            throw new ODataException(
142
                Messages::providersWrapperContainerNamespaceMustNotBeNullOrEmpty(),
143
                500
144
            );
145
        }
146
147
        return $containerNamespace;
148
    }
149
150
    /**
151
     * To get the data service configuration.
152
     *
153
     * @return IServiceConfiguration
154
     */
155
    public function getConfiguration()
156
    {
157
        return $this->config;
158
    }
159
160
    /**
161
     *  To get all entity set information,
162
     *  Note: Wrapper for IMetadataProvider::getResourceSets method implementation,
163
     *  This method returns array of ResourceSetWrapper instances but the corresponding IDSMP method
164
     *  returns array of ResourceSet instances.
165
     *
166
     *  @throws ODataException when two resource sets with the same name are encountered
167
     *
168
     *  @return ResourceSetWrapper[] The ResourceSetWrappers for the visible ResourceSets
169
     */
170
    public function getResourceSets()
171
    {
172
        $resourceSets = $this->metaProvider->getResourceSets();
173
        $resourceSetWrappers = [];
174
        $resourceSetNames = [];
175
        foreach ($resourceSets as $resourceSet) {
176
            $name = $resourceSet->getName();
177
            if (in_array($name, $resourceSetNames)) {
178
                throw new ODataException(Messages::providersWrapperEntitySetNameShouldBeUnique($name), 500);
179
            }
180
181
            $resourceSetNames[] = $name;
182
            $resourceSetWrapper = $this->_validateResourceSetAndGetWrapper($resourceSet);
183
            if (!is_null($resourceSetWrapper)) {
184
                $resourceSetWrappers[] = $resourceSetWrapper;
185
            }
186
        }
187
188
        return $resourceSetWrappers;
189
    }
190
191
    /**
192
     * This function perform the following operations
193
     *  (1) If the cache contain an entry [key, value] for the resourceset then
194
     *      return the entry-value
195
     *  (2) If the cache not contain an entry for the resourceset then validate
196
     *      the resourceset
197
     *            (a) If valid add entry as [resouceset_name, resourceSetWrapper]
198
     *            (b) if not valid add entry as [resouceset_name, null]
199
     *  Note: validating a resourceset means checking the resourceset is visible
200
     *  or not using configuration.
201
     *
202
     * @param ResourceSet $resourceSet The resourceset to validate and get the
203
     *                                 wrapper for
204
     *
205
     * @return ResourceSetWrapper|null Returns an instance if a resource set with the given name is visible
206
     */
207
    private function _validateResourceSetAndGetWrapper(ResourceSet $resourceSet)
208
    {
209
        $cacheKey = $resourceSet->getName();
210
        if (array_key_exists($cacheKey, $this->setWrapperCache)) {
211
            return $this->setWrapperCache[$cacheKey];
212
        }
213
214
        $this->validateResourceType($resourceSet->getResourceType());
215
        $wrapper = new ResourceSetWrapper($resourceSet, $this->config);
216
        $nuVal = $wrapper->isVisible() ? $wrapper : null;
217
        $this->setWrapperCache[$cacheKey] = $nuVal;
218
219
        return $this->setWrapperCache[$cacheKey];
220
    }
221
222
    /**
223
     * Validates the given instance of ResourceType.
224
     *
225
     * @param ResourceType $resourceType The ResourceType to validate
226
     *
227
     * @throws ODataException Exception if $resourceType is invalid
228
     *
229
     * @return ResourceType
230
     */
231
    private function validateResourceType(ResourceType $resourceType)
232
    {
233
        $cacheKey = $resourceType->getName();
234
        if (array_key_exists($cacheKey, $this->typeCache)) {
235
            return $this->typeCache[$cacheKey];
236
        }
237
238
        //TODO: Do validation if any for the ResourceType
239
        $this->typeCache[$cacheKey] = $resourceType;
240
241
        return $resourceType;
242
    }
243
244
    /**
245
     * To get all resource types in the data source,
246
     * Note: Wrapper for IMetadataProvider::getTypes method implementation.
247
     *
248
     * @return ResourceType[]
249
     */
250
    public function getTypes()
251
    {
252
        $resourceTypes = $this->metaProvider->getTypes();
253
        $resourceTypeNames = [];
254
        foreach ($resourceTypes as $resourceType) {
255
            if (in_array($resourceType->getName(), $resourceTypeNames)) {
256
                throw new ODataException(
257
                    Messages::providersWrapperEntityTypeNameShouldBeUnique($resourceType->getName()),
258
                    500
259
                );
260
            }
261
262
            $resourceTypeNames[] = $resourceType->getName();
263
            $this->validateResourceType($resourceType);
264
        }
265
266
        return $resourceTypes;
267
    }
268
269
    public function getSingletons()
270
    {
271
        $singletons = $this->metaProvider->getSingletons();
272
        return (null == $singletons) ? [] : $singletons;
273
    }
274
275
    /**
276
     * To get a resource set based on the specified resource set name which is
277
     * visible,
278
     * Note: Wrapper for IMetadataProvider::resolveResourceSet method
279
     * implementation.
280
     *
281
     * @param string $name Name of the resource set
282
     *
283
     * @return ResourceSetWrapper|null Returns resource set with the given name if found,
284
     *                                 NULL if resource set is set to invisible or not found
285
     */
286
    public function resolveResourceSet($name)
287
    {
288
        if (array_key_exists($name, $this->setWrapperCache)) {
289
            return $this->setWrapperCache[$name];
290
        }
291
292
        $resourceSet = $this->metaProvider->resolveResourceSet($name);
293
        if (is_null($resourceSet)) {
294
            return null;
295
        }
296
297
        return $this->_validateResourceSetAndGetWrapper($resourceSet);
298
    }
299
300
    /**
301
     * To get a resource type based on the resource set name,
302
     * Note: Wrapper for IMetadataProvider::resolveResourceType
303
     * method implementation.
304
     *
305
     * @param string $name Name of the resource set
306
     *
307
     * @throws ODataException If the ResourceType is invalid
308
     *
309
     * @return ResourceType|null resource type with the given resource set name if found else NULL
310
     */
311
    public function resolveResourceType($name)
312
    {
313
        $resourceType = $this->metaProvider->resolveResourceType($name);
314
        if (is_null($resourceType)) {
315
            return null;
316
        }
317
318
        return $this->validateResourceType($resourceType);
319
    }
320
321
322
    public function resolveSingleton($name)
323
    {
324
        $singletons = $this->metaProvider->getSingletons();
325
        if (array_key_exists($name, $singletons)) {
326
            return $singletons[$name];
327
        }
328
        return null;
329
    }
330
331
    /**
332
     * The method must return a collection of all the types derived from
333
     * $resourceType The collection returned should NOT include the type
334
     * passed in as a parameter
335
     * Note: Wrapper for IMetadataProvider::getDerivedTypes
336
     * method implementation.
337
     *
338
     * @param ResourceType $resourceType Resource to get derived resource types from
339
     *
340
     * @throws InvalidOperationException when the meat provider doesn't return an array
341
     *
342
     * @return ResourceType[]
343
     */
344
    public function getDerivedTypes(ResourceType $resourceType)
345
    {
346
        $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...
347
        if (!is_array($derivedTypes)) {
348
            throw new InvalidOperationException(
349
                Messages::metadataAssociationTypeSetInvalidGetDerivedTypesReturnType($resourceType->getName())
350
            );
351
        }
352
353
        foreach ($derivedTypes as $derivedType) {
354
            $this->validateResourceType($derivedType);
355
        }
356
357
        return $derivedTypes;
358
    }
359
360
    /**
361
     * Returns true if $resourceType represents an Entity Type which has derived
362
     * Entity Types, else false.
363
     * Note: Wrapper for IMetadataProvider::hasDerivedTypes method
364
     * implementation.
365
     *
366
     * @param ResourceType $resourceType Resource to check for derived resource
367
     *                                   types
368
     *
369
     * @throws ODataException If the ResourceType is invalid
370
     *
371
     * @return bool
372
     */
373
    public function hasDerivedTypes(ResourceType $resourceType)
374
    {
375
        $this->validateResourceType($resourceType);
376
377
        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...
378
    }
379
380
    /**
381
     * Gets the visible resource properties for the given resource type from the given resource set wrapper.
382
     *
383
     * @param ResourceSetWrapper $setWrapper Resource set wrapper in question
384
     * @param ResourceType $resourceType Resource type in question
385
     *
386
     * @return ResourceProperty[] Collection of visible resource properties from the given resource set wrapper
387
     *                            and resource type
388
     */
389
    public function getResourceProperties(ResourceSetWrapper $setWrapper, ResourceType $resourceType)
390
    {
391
        if ($resourceType->getResourceTypeKind() != ResourceTypeKind::ENTITY) {
392
            //Complex resource type
393
            return $resourceType->getAllProperties();
394
        }
395
        //TODO: move this to doctrine annotations
396
        $cacheKey = $setWrapper->getName() . '_' . $resourceType->getFullName();
397
        if (!array_key_exists($cacheKey, $this->propertyCache)) {
398
            //Fill the cache
399
            $this->propertyCache[$cacheKey] = [];
400
            foreach ($resourceType->getAllProperties() as $resourceProperty) {
401
                //Check whether this is a visible navigation property
402
                //TODO: is this broken?? see #87
403
                if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY
404
                    && !is_null($this->getResourceSetWrapperForNavigationProperty(
405
                        $setWrapper,
406
                        $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...
407
                        $resourceProperty
408
                    ))
409
                ) {
410
                    $this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty;
411
                } else {
412
                    //primitive, bag or complex property
413
                    $this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty;
414
                }
415
            }
416
        }
417
418
        return $this->propertyCache[$cacheKey];
419
    }
420
421
    /**
422
     * Gets the target resource set wrapper for the given navigation property,
423
     * source resource set wrapper and the source resource type.
424
     *
425
     * @param ResourceSetWrapper $resourceSetWrapper Source resource set
426
     * @param ResourceEntityType $resourceType Source resource type
427
     * @param ResourceProperty   $navigationResourceProperty Navigation property
428
     *
429
     * @return ResourceSetWrapper|null Returns instance of ResourceSetWrapper
430
     *                                 (describes the entity set and associated configuration) for the
431
     *                                 given navigation property. returns NULL if resourceset for the
432
     *                                 navigation property is invisible or if metadata provider returns
433
     *                                 null resource association set
434
     */
435
    public function getResourceSetWrapperForNavigationProperty(
436
        ResourceSetWrapper $resourceSetWrapper,
437
        ResourceEntityType $resourceType,
438
        ResourceProperty $navigationResourceProperty
439
    ) {
440
        $associationSet = $this->getResourceAssociationSet(
441
            $resourceSetWrapper,
442
            $resourceType,
443
            $navigationResourceProperty
444
        );
445
446
        if (!is_null($associationSet)) {
447
            $relatedAssociationSetEnd = $associationSet->getRelatedResourceAssociationSetEnd(
448
                $resourceSetWrapper->getResourceSet(),
449
                $resourceType,
450
                $navigationResourceProperty
451
            );
452
453
            return $this->_validateResourceSetAndGetWrapper(
454
                $relatedAssociationSetEnd->getResourceSet()
455
            );
456
        }
457
        return null;
458
    }
459
460
    /**
461
     * Gets the ResourceAssociationSet instance for the given source association end,
462
     * Note: Wrapper for IMetadataProvider::getResourceAssociationSet
463
     * method implementation.
464
     *
465
     * @param ResourceSet           $set      Resource set of the source association end
466
     * @param ResourceEntityType    $type     Resource type of the source association end
467
     * @param ResourceProperty      $property Resource property of the source association end
468
     *
469
     * @return ResourceAssociationSet|null Returns ResourceAssociationSet for the source
470
     *                                     association end, NULL if no such
471
     *                                     association end or resource set in the
472
     *                                     other end of the association is invisible
473
     */
474
    public function getResourceAssociationSet(
475
        ResourceSet $set,
476
        ResourceEntityType $type,
477
        ResourceProperty $property
478
    ) {
479
        $type = $this->getResourceTypeWherePropertyIsDeclared($type, $property);
480
        // usage below requires $type to not be null - so kaboom as early as possible
481
        assert(null != $type, 'Resource type obtained from property must not be null.');
482
483
        $associationSet = $this->metaProvider->getResourceAssociationSet(
484
            $set,
485
            $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...
486
            $property
487
        );
488
        assert(
489
            null == $associationSet || $associationSet instanceof ResourceAssociationSet,
490
            "Retrieved resource assocation must be either null or an instance of ResourceAssociationSet"
491
        );
492
493
        if (!is_null($associationSet)) {
494
            $thisAssociationSetEnd = $associationSet->getResourceAssociationSetEnd(
495
                $set,
496
                $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...
497
                $property
498
            );
499
500
            $relatedAssociationSetEnd = $associationSet->getRelatedResourceAssociationSetEnd(
501
                $set,
502
                $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...
503
                $property
504
            );
505
506
            //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...
507
            //is null means the associationset we got from the IDSMP::getResourceAssociationSet is invalid.
508
509
            //Return null, if either AssociationSet's End1 or End2's resourceset name
510
            //doesn't match the name of resource set wrapper (param1) and resource type is not assignable
511
            //from given resource type (param2)
512
            if (is_null($thisAssociationSetEnd) || is_null($relatedAssociationSetEnd)) {
513
                throw new ODataException(
514
                    Messages::providersWrapperIDSMPGetResourceSetReturnsInvalidResourceSet(
515
                        $set->getName(),
516
                        $type->getFullName(),
517
                        $property->getName()
518
                    ),
519
                    500
520
                );
521
            }
522
523
            $relatedResourceSetWrapper = $this->_validateResourceSetAndGetWrapper(
524
                $relatedAssociationSetEnd->getResourceSet()
525
            );
526
            if ($relatedResourceSetWrapper === null) {
527
                $associationSet = null;
528
            } else {
529
                $this->validateResourceType($thisAssociationSetEnd->getResourceType());
530
                $this->validateResourceType($relatedAssociationSetEnd->getResourceType());
531
            }
532
        }
533
        assert(
534
            null == $associationSet || $associationSet instanceof ResourceAssociationSet,
535
            "Retrieved resource assocation must be either null or an instance of ResourceAssociationSet"
536
        );
537
538
        return $associationSet;
539
    }
540
541
    /**
542
     * Gets the resource type on which the resource property is declared on,
543
     * If property is not declared in the given resource type, then this
544
     * function drill down to the inheritance hierarchy of the given resource
545
     * type to find out the base class in which the property is declared.
546
     *
547
     * @param ResourceType     $type     The resource type to start looking
548
     * @param ResourceProperty $property The resource property in question
549
     *
550
     * @return ResourceType|null Returns reference to the ResourceType on which
551
     *                           the $property is declared, NULL if
552
     *                           $property is not declared anywhere
553
     *                           in the inheritance hierarchy
554
     */
555
    private function getResourceTypeWherePropertyIsDeclared(ResourceType $type, ResourceProperty $property)
556
    {
557
        while (null !== $type) {
558
            if (null !== $type->resolvePropertyDeclaredOnThisType($property->getName())) {
559
                break;
560
            }
561
562
            $type = $type->getBaseType();
563
        }
564
565
        return $type;
566
    }
567
568
    /**
569
     * Wrapper function over _validateResourceSetAndGetWrapper function.
570
     *
571
     * @param ResourceSet $resourceSet see the comments of _validateResourceSetAndGetWrapper
572
     *
573
     * @return ResourceSetWrapper|null see the comments of _validateResourceSetAndGetWrapper
574
     */
575
    public function validateResourceSetAndGetWrapper(ResourceSet $resourceSet)
576
    {
577
        return $this->_validateResourceSetAndGetWrapper($resourceSet);
578
    }
579
580
    /**
581
     * Gets the Edm Schema version compliance to the metadata.
582
     *
583
     * @return EdmSchemaVersion
584
     */
585
    public function getEdmSchemaVersion()
586
    {
587
        //The minimal schema version for custom provider is 1.1
588
        return EdmSchemaVersion::VERSION_1_DOT_1;
589
    }
590
591
    /**
592
     * Gets the underlying custom expression provider, the end developer is
593
     * responsible for implementing IExpressionProvider if he choose for.
594
     *
595
     * @return IExpressionProvider Instance of IExpressionProvider implementation
596
     */
597
    public function getExpressionProvider()
598
    {
599
        return $this->providerWrapper->getExpressionProvider();
600
    }
601
602
    /**
603
     * Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters
604
     * If the query provider can not handle ordered paging, it must return the entire result set and POData will
605
     * perform the ordering and paging.
606
     *
607
     * @return bool True if the query provider can handle ordered paging, false if POData should perform the paging
608
     */
609
    public function handlesOrderedPaging()
610
    {
611
        return $this->providerWrapper->handlesOrderedPaging();
612
    }
613
614
    /**
615
     * Gets collection of entities belongs to an entity set.
616
     *
617
     * @param QueryType             $queryType   Indicates if this is a query for a count, entities, or entities with a
618
     *                                           count
619
     * @param ResourceSet           $resourceSet The entity set containing the entities that need to be fetched
620
     * @param FilterInfo            $filterInfo  Represents the $filter parameter of the OData query.
621
     *                                           NULL if no $filter specified
622
     * @param InternalOrderByInfo   $orderBy     The orderBy information
623
     * @param int                   $top         The top count
624
     * @param int                   $skip        The skip count
625
     * @param InternalSkipTokenInfo $skipToken   The skip token
626
     *
627
     * @return QueryResult
628
     */
629
    public function getResourceSet(
630
        QueryType $queryType,
631
        ResourceSet $resourceSet,
632
        FilterInfo $filterInfo = null,
633
        InternalOrderByInfo $orderBy = null,
634
        $top = null,
635
        $skip = null,
636
        InternalSkipTokenInfo $skipToken = null
637
    ) {
638
        return $this->providerWrapper->getResourceSet(
639
            $queryType,
640
            $resourceSet,
641
            $filterInfo,
642
            $orderBy,
643
            $top,
644
            $skip,
645
            $skipToken
646
        );
647
    }
648
649
    /**
650
     * Gets an entity instance from an entity set identified by a key.
651
     *
652
     * @param ResourceSet   $resourceSet   The entity set containing the entity to fetch
653
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
654
     *
655
     * @return object|null Returns entity instance if found else null
656
     */
657
    public function getResourceFromResourceSet(ResourceSet $resourceSet, KeyDescriptor $keyDescriptor)
658
    {
659
        return $this->providerWrapper->getResourceFromResourceSet($resourceSet, $keyDescriptor);
660
    }
661
662
    /**
663
     * Puts an entity instance to entity set identified by a key.
664
     *
665
     * @param ResourceSet   $resourceSet   The entity set containing the entity to update
666
     * @param KeyDescriptor $keyDescriptor The key identifying the entity to update
667
     *
668
     * @return bool|null Returns result of executiong query
669
     */
670
    public function putResource(
671
        ResourceSet $resourceSet,
672
        KeyDescriptor $keyDescriptor,
673
        $data
674
    ) {
675
        return $this->providerWrapper->putResource(
676
            $resourceSet,
677
            $keyDescriptor,
678
            $data
679
        );
680
    }
681
682
    /**
683
     * Get related resource set for a resource.
684
     *
685
     * @param QueryType        $queryType         Indicates if this is a query for a count, entities, or entities
686
     *                                            with a count
687
     * @param ResourceSet      $sourceResourceSet The entity set containing the source entity
688
     * @param object           $sourceEntity      The source entity instance
689
     * @param ResourceSet      $targetResourceSet The resource set of containing the target of the navigation property
690
     * @param ResourceProperty $targetProperty    The navigation property to retrieve
691
     * @param FilterInfo|null  $filterInfo        Represents the $filter parameter of the OData query.
692
     *                                            NULL if no $filter specified
693
     * @param mixed            $orderBy           sorted order if we want to get the data in some specific order
694
     * @param int              $top               number of records which  need to be skip
695
     * @param string           $skip              value indicating what records to skip
696
     *
697
     * @throws ODataException
698
     *
699
     * @return QueryResult
700
     */
701
    public function getRelatedResourceSet(
702
        QueryType $queryType,
703
        ResourceSet $sourceResourceSet,
704
        $sourceEntity,
705
        ResourceSet $targetResourceSet,
706
        ResourceProperty $targetProperty,
707
        $filterInfo,
708
        $orderBy,
709
        $top,
710
        $skip
711
    ) {
712
        return $this->providerWrapper->getRelatedResourceSet(
713
            $queryType,
714
            $sourceResourceSet,
715
            $sourceEntity,
716
            $targetResourceSet,
717
            $targetProperty,
718
            $filterInfo,
0 ignored issues
show
Bug introduced by
It seems like $filterInfo defined by parameter $filterInfo on line 707 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...
719
            $orderBy,
720
            $top,
721
            $skip
722
        );
723
    }
724
725
    /**
726
     * Gets a related entity instance from an entity set identified by a key.
727
     *
728
     * @param ResourceSet      $sourceResourceSet The entity set related to the entity to be fetched
729
     * @param object           $sourceEntity      The related entity instance
730
     * @param ResourceSet      $targetResourceSet The entity set from which entity needs to be fetched
731
     * @param ResourceProperty $targetProperty    The metadata of the target property
732
     * @param KeyDescriptor    $keyDescriptor     The key to identify the entity to be fetched
733
     *
734
     * @return object|null Returns entity instance if found else null
735
     */
736
    public function getResourceFromRelatedResourceSet(
737
        ResourceSet $sourceResourceSet,
738
        $sourceEntity,
739
        ResourceSet $targetResourceSet,
740
        ResourceProperty $targetProperty,
741
        KeyDescriptor $keyDescriptor
742
    ) {
743
        return $this->providerWrapper->getResourceFromRelatedResourceSet(
744
            $sourceResourceSet,
745
            $sourceEntity,
746
            $targetResourceSet,
747
            $targetProperty,
748
            $keyDescriptor
749
        );
750
    }
751
752
    /**
753
     * Get related resource for a resource.
754
     *
755
     * @param ResourceSet      $sourceResourceSet The source resource set
756
     * @param object           $sourceEntity      The source resource
757
     * @param ResourceSet      $targetResourceSet The resource set of the navigation
758
     *                                            property
759
     * @param ResourceProperty $targetProperty    The navigation property to be
760
     *                                            retrieved
761
     *
762
     * @return object|null The related resource if exists else null
763
     */
764
    public function getRelatedResourceReference(
765
        ResourceSet $sourceResourceSet,
766
        $sourceEntity,
767
        ResourceSet $targetResourceSet,
768
        ResourceProperty $targetProperty
769
    ) {
770
        return $this->providerWrapper->getRelatedResourceReference(
771
            $sourceResourceSet,
772
            $sourceEntity,
773
            $targetResourceSet,
774
            $targetProperty
775
        );
776
    }
777
778
    /**
779
     * Updates a resource.
780
     *
781
     * @param ResourceSet   $sourceResourceSet    The entity set containing the source entity
782
     * @param object        $sourceEntityInstance The source entity instance
783
     * @param KeyDescriptor $keyDescriptor        The key identifying the entity to fetch
784
     * @param object        $data                 The New data for the entity instance.
785
     * @param bool          $shouldUpdate         Should undefined values be updated or reset to default
786
     *
787
     * @return object|null The new resource value if it is assignable or throw exception for null.
788
     */
789
    public function updateResource(
790
        ResourceSet $sourceResourceSet,
791
        $sourceEntityInstance,
792
        KeyDescriptor $keyDescriptor,
793
        $data,
794
        $shouldUpdate = false
795
    ) {
796
        return $this->providerWrapper->updateResource(
797
            $sourceResourceSet,
798
            $sourceEntityInstance,
799
            $keyDescriptor,
800
            $data,
801
            $shouldUpdate
802
        );
803
    }
804
805
    /**
806
     * Delete resource from a resource set.
807
     *
808
     * @param ResourceSet $sourceResourceSet
809
     * @param object      $sourceEntityInstance
810
     *
811
     * return bool true if resources sucessfully deteled, otherwise false.
812
     */
813
    public function deleteResource(
814
        ResourceSet $sourceResourceSet,
815
        $sourceEntityInstance
816
    ) {
817
        return $this->providerWrapper->deleteResource(
818
            $sourceResourceSet,
819
            $sourceEntityInstance
820
        );
821
    }
822
823
    /**
824
     * @param ResourceSet $resourceSet          The entity set containing the entity to fetch
825
     * @param object      $sourceEntityInstance The source entity instance
826
     * @param object      $data                 The New data for the entity instance.
827
     *
828
     * returns object|null returns the newly created model if sucessful or null if model creation failed.
829
     */
830
    public function createResourceforResourceSet(
831
        ResourceSet $resourceSet,
832
        $sourceEntityInstance,
833
        $data
834
    ) {
835
        return $this->providerWrapper->createResourceforResourceSet(
836
            $resourceSet,
837
            $sourceEntityInstance,
838
            $data
839
        );
840
    }
841
842
    public function getMetadataXML()
843
    {
844
        return $this->metaProvider->getXML();
845
    }
846
}
847