ProvidersWrapper::getRelatedResourceSet()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 11
nc 1
nop 10
dl 0
loc 23
rs 9.9
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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