Completed
Branch master (990ea3)
by Bálint
05:57 queued 02:43
created
src/POData/HttpProcessUtility.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -477,7 +477,7 @@  discard block
 block discarded – undo
477 477
     /**
478 478
      * To check whether the given character is a HTTP seperator character.
479 479
      *
480
-     * @param char $char The character to inspect.
480
+     * @param string $char The character to inspect.
481 481
      *
482 482
      * @return boolean True if the given character is a valid HTTP seperator
483 483
      *                 character, False otherwise.
@@ -687,7 +687,7 @@  discard block
 block discarded – undo
687 687
      * Verifies whether the specified character is a valid separator in
688 688
        an HTTP header list of element.
689 689
      *
690
-     * @param char $c Character to verify
690
+     * @param string $c Character to verify
691 691
      *
692 692
      * @return boolean true if c is a valid character for separating elements;
693 693
      *                 false otherwise.
Please login to merge, or discard this patch.
Indentation   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -103,7 +103,7 @@
 block discarded – undo
103 103
                 //the rest look like QSPs..kinda so we can do this
104 104
                 parse_str(implode("&", $candidateParts), $candidateParts);
105 105
                 if (array_key_exists('odata', $candidateParts)) {
106
-                   $candidateODataValue = $candidateParts['odata'];
106
+                    $candidateODataValue = $candidateParts['odata'];
107 107
                 }
108 108
             }
109 109
 
Please login to merge, or discard this patch.
src/POData/Writers/Metadata/MetadataWriter.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -211,7 +211,7 @@
 block discarded – undo
211 211
      * Write an entity type and associated attributes.
212 212
      *
213 213
      * @param ResourceType $resourceType                            Resource type
214
-     * @param array        $associationTypesInResourceTypeNamespace Collection of
214
+     * @param ResourceAssociationType[]        $associationTypesInResourceTypeNamespace Collection of
215 215
      * association types for the given resource types
216 216
      * array(string, AssociationType)
217 217
      *
Please login to merge, or discard this patch.
Indentation   -1 removed lines patch added patch discarded remove patch
@@ -187,7 +187,6 @@
 block discarded – undo
187 187
      * Write all resource types (entity and complex types)
188 188
      *
189 189
      * @param ResourceType[] $resourceTypes resource types array
190
-
191 190
      * @param ResourceAssociationType[] $associationTypesInResourceTypesNamespace collection of
192 191
      * association types for the given resource types
193 192
      * array(string, AssociationType)
Please login to merge, or discard this patch.
src/POData/Common/Version.php 1 patch
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -122,12 +122,12 @@  discard block
 block discarded – undo
122 122
     /** @var Version[] */
123 123
     private static $fixedVersion;
124 124
 
125
-    private static function fillVersions(){
126
-        if(is_null(self::$fixedVersion)){
125
+    private static function fillVersions() {
126
+        if (is_null(self::$fixedVersion)) {
127 127
             self::$fixedVersion = array(
128
-                1 => new Version(1,0),
129
-                2 => new Version(2,0),
130
-                3 => new Version(3,0),
128
+                1 => new Version(1, 0),
129
+                2 => new Version(2, 0),
130
+                3 => new Version(3, 0),
131 131
             );
132 132
         }
133 133
     }
@@ -139,13 +139,13 @@  discard block
 block discarded – undo
139 139
     }
140 140
 
141 141
 
142
-    public static function v2(){
142
+    public static function v2() {
143 143
         self::fillVersions();
144 144
         return self::$fixedVersion[2];
145 145
     }
146 146
 
147 147
 
148
-    public static function v3(){
148
+    public static function v3() {
149 149
         self::fillVersions();
150 150
         return self::$fixedVersion[3];
151 151
     }
Please login to merge, or discard this patch.
src/POData/BaseService.php 1 patch
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -317,11 +317,11 @@  discard block
 block discarded – undo
317 317
         $registry->register(new JsonODataV1Writer());
318 318
         $registry->register(new AtomODataWriter($serviceURI));
319 319
 
320
-        if($serviceVersion->compare(Version::v2()) > -1){
320
+        if ($serviceVersion->compare(Version::v2()) > -1) {
321 321
             $registry->register(new JsonODataV2Writer());
322 322
         }
323 323
 
324
-        if($serviceVersion->compare(Version::v3()) > -1){
324
+        if ($serviceVersion->compare(Version::v3()) > -1) {
325 325
             $registry->register(new JsonLightODataWriter(JsonLightMetadataLevel::NONE(), $serviceURI));
326 326
             $registry->register(new JsonLightODataWriter(JsonLightMetadataLevel::MINIMAL(), $serviceURI));
327 327
             $registry->register(new JsonLightODataWriter(JsonLightMetadataLevel::FULL(), $serviceURI));
@@ -352,7 +352,7 @@  discard block
 block discarded – undo
352 352
 
353 353
         if (is_null($responseContentType) && $request->getTargetKind() != TargetKind::MEDIA_RESOURCE()) {
354 354
             //the responseContentType can ONLY be null if it's a stream (media resource) and that stream is storing null as the content type
355
-            throw new ODataException( Messages::unsupportedMediaType(), 415 );
355
+            throw new ODataException(Messages::unsupportedMediaType(), 415);
356 356
         }
357 357
 
358 358
         $odataModelInstance = null;
@@ -529,10 +529,10 @@  discard block
 block discarded – undo
529 529
 
530 530
         //if the $format header is present it overrides the accepts header
531 531
         $format = $host->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_FORMAT);
532
-        if(!is_null($format)){
532
+        if (!is_null($format)) {
533 533
 
534 534
             //There's a strange edge case..if application/json is supplied and it's V3
535
-            if($format == MimeTypes::MIME_APPLICATION_JSON && $requestVersion == Version::v3()){
535
+            if ($format == MimeTypes::MIME_APPLICATION_JSON && $requestVersion == Version::v3()) {
536 536
                 //then it's actual minimalmetadata
537 537
                 //TODO: should this be done with the header text too?
538 538
                 $format = MimeTypes::MIME_APPLICATION_JSON_MINIMAL_META;
@@ -548,7 +548,7 @@  discard block
 block discarded – undo
548 548
         //getTargetKind doesn't deal with link resources directly and this can change things
549 549
         $targetKind = $request->isLinkUri() ? TargetKind::LINK() : $request->getTargetKind();
550 550
 
551
-        switch($targetKind){
551
+        switch ($targetKind) {
552 552
             case TargetKind::METADATA():
553 553
                 return HttpProcessUtility::selectMimeType(
554 554
                     $requestAcceptText,
@@ -626,7 +626,7 @@  discard block
 block discarded – undo
626 626
                 );
627 627
 
628 628
             case TargetKind::MEDIA_RESOURCE():
629
-                if (!$request->isNamedStream() && !$request->getTargetResourceType()->isMediaLinkEntry()){
629
+                if (!$request->isNamedStream() && !$request->getTargetResourceType()->isMediaLinkEntry()) {
630 630
                     throw ODataException::createBadRequestError(
631 631
                         Messages::badRequestInvalidUriForMediaResource(
632 632
                             $host->getAbsoluteRequestUri()->getUrlAsString()
@@ -660,7 +660,7 @@  discard block
 block discarded – undo
660 660
 
661 661
 
662 662
         //If we got here, we just don't know what it is...
663
-        throw new ODataException( Messages::unsupportedMediaType(), 415 );
663
+        throw new ODataException(Messages::unsupportedMediaType(), 415);
664 664
 
665 665
     }
666 666
 
@@ -790,16 +790,16 @@  discard block
 block discarded – undo
790 790
             try {
791 791
 
792 792
                 //TODO #88...also this seems like dupe work
793
-                $reflectionProperty  = new \ReflectionProperty($entryObject, $eTagProperty->getName() );
793
+                $reflectionProperty = new \ReflectionProperty($entryObject, $eTagProperty->getName());
794 794
                 $value = $reflectionProperty->getValue($entryObject);
795 795
             } catch (\ReflectionException $reflectionException) {
796 796
                 throw ODataException::createInternalServerError(
797
-                    Messages::failedToAccessProperty($eTagProperty->getName(), $resourceType->getName() )
797
+                    Messages::failedToAccessProperty($eTagProperty->getName(), $resourceType->getName())
798 798
                 );
799 799
             }
800 800
 
801 801
             if (is_null($value)) {
802
-                $eTag = $eTag . $comma. 'null';
802
+                $eTag = $eTag . $comma . 'null';
803 803
             } else {
804 804
                 $eTag = $eTag . $comma . $type->convertToOData($value);
805 805
             }
Please login to merge, or discard this patch.
src/POData/Providers/Expression/PHPExpressionProvider.php 1 patch
Spacing   +6 added lines, -7 removed lines patch added patch discarded remove patch
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
      */
94 94
     public function onLogicalExpression($expressionType, $left, $right)
95 95
     {
96
-        switch($expressionType) {
96
+        switch ($expressionType) {
97 97
             case ExpressionType::AND_LOGICAL:
98 98
                 return $this->_prepareBinaryExpression(self::LOGICAL_AND, $left, $right);
99 99
 
@@ -116,7 +116,7 @@  discard block
 block discarded – undo
116 116
      */
117 117
     public function onArithmeticExpression($expressionType, $left, $right)
118 118
     {
119
-        switch($expressionType) {
119
+        switch ($expressionType) {
120 120
             case ExpressionType::MULTIPLY:
121 121
                 return $this->_prepareBinaryExpression(self::MULTIPLY, $left, $right);
122 122
 
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
      */
149 149
     public function onRelationalExpression($expressionType, $left, $right)
150 150
     {
151
-        switch($expressionType) {
151
+        switch ($expressionType) {
152 152
             case ExpressionType::GREATERTHAN:
153 153
                 return $this->_prepareBinaryExpression(self::GREATER_THAN, $left, $right);
154 154
 
@@ -182,7 +182,7 @@  discard block
 block discarded – undo
182 182
      */
183 183
     public function onUnaryExpression($expressionType, $child)
184 184
     {
185
-        switch($expressionType) {
185
+        switch ($expressionType) {
186 186
             case ExpressionType::NEGATE:
187 187
                 return $this->_prepareUnaryExpression(self::NEGATE, $child);
188 188
 
@@ -245,7 +245,7 @@  discard block
 block discarded – undo
245 245
      */
246 246
     public function onFunctionCallExpression($functionDescription, $params)
247 247
     {
248
-        switch($functionDescription->name) {
248
+        switch ($functionDescription->name) {
249 249
             case ODataConstants::STRFUN_COMPARE:
250 250
                 return "strcmp($params[0], $params[1])";
251 251
 
@@ -272,8 +272,7 @@  discard block
 block discarded – undo
272 272
 
273 273
             case ODataConstants::STRFUN_SUBSTRING:
274 274
                 return count($params) == 3 ?
275
-                    "substr($params[0], $params[1], $params[2])" :
276
-                    "substr($params[0], $params[1])";
275
+                    "substr($params[0], $params[1], $params[2])" : "substr($params[0], $params[1])";
277 276
 
278 277
             case ODataConstants::STRFUN_SUBSTRINGOF:
279 278
                 return "(strpos($params[1], $params[0]) !== false)";
Please login to merge, or discard this patch.
src/POData/Providers/Expression/MySQLExpressionProvider.php 1 patch
Spacing   +12 added lines, -13 removed lines patch added patch discarded remove patch
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
      */
85 85
     public function onLogicalExpression($expressionType, $left, $right)
86 86
     {
87
-        switch($expressionType) {
87
+        switch ($expressionType) {
88 88
             case ExpressionType::AND_LOGICAL:
89 89
                 return $this->_prepareBinaryExpression(self::LOGICAL_AND, $left, $right);
90 90
 
@@ -107,7 +107,7 @@  discard block
 block discarded – undo
107 107
      */
108 108
     public function onArithmeticExpression($expressionType, $left, $right)
109 109
     {
110
-        switch($expressionType) {
110
+        switch ($expressionType) {
111 111
             case ExpressionType::MULTIPLY:
112 112
                 return $this->_prepareBinaryExpression(self::MULTIPLY, $left, $right);
113 113
 
@@ -139,7 +139,7 @@  discard block
 block discarded – undo
139 139
      */
140 140
     public function onRelationalExpression($expressionType, $left, $right)
141 141
     {
142
-        switch($expressionType) {
142
+        switch ($expressionType) {
143 143
             case ExpressionType::GREATERTHAN:
144 144
                 return $this->_prepareBinaryExpression(self::GREATER_THAN, $left, $right);
145 145
 
@@ -173,7 +173,7 @@  discard block
 block discarded – undo
173 173
      */
174 174
     public function onUnaryExpression($expressionType, $child)
175 175
     {
176
-        switch($expressionType) {
176
+        switch ($expressionType) {
177 177
             case ExpressionType::NEGATE:
178 178
                 return $this->_prepareUnaryExpression(self::NEGATE, $child);
179 179
 
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
      */
240 240
     public function onFunctionCallExpression($functionDescription, $params)
241 241
     {
242
-        switch($functionDescription->name) {
242
+        switch ($functionDescription->name) {
243 243
             case ODataConstants::STRFUN_COMPARE:
244 244
                 return "STRCMP($params[0], $params[1])";
245 245
 
@@ -266,8 +266,7 @@  discard block
 block discarded – undo
266 266
 
267 267
             case ODataConstants::STRFUN_SUBSTRING:
268 268
                 return count($params) == 3 ?
269
-                    "SUBSTRING($params[0], $params[1] + 1, $params[2])" :
270
-                    "SUBSTRING($params[0], $params[1] + 1)";
269
+                    "SUBSTRING($params[0], $params[1] + 1, $params[2])" : "SUBSTRING($params[0], $params[1] + 1)";
271 270
 
272 271
             case ODataConstants::STRFUN_SUBSTRINGOF:
273 272
                 return "(LOCATE($params[0], $params[1]) > 0)";
@@ -285,22 +284,22 @@  discard block
 block discarded – undo
285 284
                 return "DATETIMECMP($params[0]; $params[1])";
286 285
 
287 286
             case ODataConstants::DATETIME_YEAR:
288
-                return "EXTRACT(YEAR from ".$params[0].")";
287
+                return "EXTRACT(YEAR from " . $params[0] . ")";
289 288
 
290 289
             case ODataConstants::DATETIME_MONTH:
291
-                return "EXTRACT(MONTH from ".$params[0].")";
290
+                return "EXTRACT(MONTH from " . $params[0] . ")";
292 291
 
293 292
             case ODataConstants::DATETIME_DAY:
294
-                return "EXTRACT(DAY from ".$params[0].")";
293
+                return "EXTRACT(DAY from " . $params[0] . ")";
295 294
 
296 295
             case ODataConstants::DATETIME_HOUR:
297
-                return "EXTRACT(HOUR from ".$params[0].")";
296
+                return "EXTRACT(HOUR from " . $params[0] . ")";
298 297
 
299 298
             case ODataConstants::DATETIME_MINUTE:
300
-                return "EXTRACT(MINUTE from ".$params[0].")";
299
+                return "EXTRACT(MINUTE from " . $params[0] . ")";
301 300
 
302 301
             case ODataConstants::DATETIME_SECOND:
303
-                return "EXTRACT(SECOND from ".$params[0].")";
302
+                return "EXTRACT(SECOND from " . $params[0] . ")";
304 303
 
305 304
             case ODataConstants::MATHFUN_ROUND:
306 305
                 return "ROUND($params[0])";
Please login to merge, or discard this patch.
src/POData/Providers/ProvidersWrapper.php 2 patches
Indentation   +956 added lines, -956 removed lines patch added patch discarded remove patch
@@ -32,960 +32,960 @@
 block discarded – undo
32 32
  */
33 33
 class ProvidersWrapper
34 34
 {
35
-	/**
36
-	 * Holds reference to IMetadataProvider implementation
37
-	 *
38
-	 * @var IMetadataProvider
39
-	 */
40
-	private $metaProvider;
41
-
42
-	/**
43
-	 * Holds reference to IQueryProvider implementation
44
-	 *
45
-	 * @var IQueryProvider
46
-	 *
47
-	 */
48
-	private $queryProvider;
49
-
50
-	/**
51
-	 * Holds reference to IServiceConfiguration implementation
52
-	 *
53
-	 * @var ServiceConfiguration
54
-	 */
55
-	private $config;
56
-
57
-
58
-	/**
59
-	 * Cache for ResourceProperties of a resource type that belongs to a
60
-	 * resource set. An entry (ResourceProperty collection) in this cache
61
-	 * contains only the visible properties of ResourceType.
62
-	 *
63
-	 * @var array(string, array(string, ResourceProperty))
64
-	 */
65
-	private $propertyCache;
66
-
67
-	/**
68
-	 * Cache for ResourceSetWrappers. If ResourceSet is invisible value will
69
-	 * be null.
70
-	 *
71
-	 * @var ResourceSetWrapper[] indexed by resource set name
72
-	 */
73
-	private $setWrapperCache;
74
-
75
-	/**
76
-	 * Cache for ResourceTypes
77
-	 *
78
-	 * @var ResourceType[] indexed by resource type name
79
-	 */
80
-	private $typeCache;
81
-
82
-	/**
83
-	 * Cache for ResourceAssociationSet. If ResourceAssociationSet is invisible
84
-	 * value will be null.
85
-	 *
86
-	 * @var ResourceAssociationSet[] indexed by name
87
-	 */
88
-	private $associationSetCache;
89
-
90
-	/**
91
-	 * Creates a new instance of ProvidersWrapper
92
-	 *
93
-	 * @param IMetadataProvider $metadataProvider Reference to IMetadataProvider implementation
94
-	 * @param IQueryProvider    $queryProvider    Reference to IQueryProvider implementation
95
-	 * @param ServiceConfiguration    $configuration    Reference to IServiceConfiguration implementation
96
-	 */
97
-	public function __construct(IMetadataProvider $metadataProvider, IQueryProvider $queryProvider, ServiceConfiguration $configuration)
98
-	{
99
-		$this->metaProvider = $metadataProvider;
100
-		$this->queryProvider = $queryProvider;
101
-		$this->config = $configuration;
102
-		$this->setWrapperCache = array();
103
-		$this->typeCache = array();
104
-		$this->associationSetCache = array();
105
-		$this->propertyCache = array();
106
-	}
107
-
108
-	//Wrappers for IMetadataProvider methods
109
-
110
-	/**
111
-	 * To get the Container name for the data source,
112
-	 * Note: Wrapper for IMetadataProvider::getContainerName method
113
-	 * implementation
114
-	 *
115
-	 * @return string that contains the name of the container
116
-	 *
117
-	 * @throws ODataException Exception if implementation returns empty container name
118
-	 *
119
-	 */
120
-	public function getContainerName()
121
-	{
122
-		$containerName = $this->metaProvider->getContainerName();
123
-		if (empty($containerName)) {
124
-			throw new ODataException(
125
-				Messages::providersWrapperContainerNameMustNotBeNullOrEmpty(),
126
-				500
127
-			);
128
-		}
129
-
130
-		return $containerName;
131
-	}
132
-
133
-	/**
134
-	 * To get Namespace name for the data source,
135
-	 * Note: Wrapper for IMetadataProvider::getContainerNamespace method implementation
136
-	 *
137
-	 * @return string that contains the namespace name.
138
-	 *
139
-	 * @throws ODataException Exception if implementation returns empty container namespace
140
-	 *
141
-	 */
142
-	public function getContainerNamespace()
143
-	{
144
-		$containerNamespace = $this->metaProvider->getContainerNamespace();
145
-		if (empty($containerNamespace)) {
146
-			throw new ODataException(
147
-				Messages::providersWrapperContainerNamespaceMustNotBeNullOrEmpty(),
148
-				500
149
-			);
150
-		}
151
-
152
-		return $containerNamespace;
153
-	}
154
-
155
-	/**
156
-	 * To get the data service configuration
157
-	 *
158
-	 * @return ServiceConfiguration
159
-	 */
160
-	public function getConfiguration()
161
-	{
162
-		return $this->config;
163
-	}
164
-
165
-	/**
166
-	 *  To get all entity set information,
167
-	 *  Note: Wrapper for IMetadataProvider::getResourceSets method implementation,
168
-	 *  This method returns array of ResourceSetWrapper instances but the corresponding IDSMP method returns array of ResourceSet instances
169
-	 *
170
-	 *  @return ResourceSetWrapper[] The ResourceSetWrappers for the visible ResourceSets
171
-	 *  @throws ODataException when two resource sets with the same name are encountered
172
-	 *
173
-	 */
174
-	public function getResourceSets()
175
-	{
176
-		$resourceSets = $this->metaProvider->getResourceSets();
177
-		$resourceSetWrappers = array();
178
-		$resourceSetNames = array();
179
-		foreach ($resourceSets as $resourceSet) {
180
-			$name = $resourceSet->getName();
181
-			if (in_array($name, $resourceSetNames)) {
182
-				throw new ODataException(Messages::providersWrapperEntitySetNameShouldBeUnique($name), 500);
183
-			}
184
-
185
-			$resourceSetNames[] = $name;
186
-			$resourceSetWrapper = $this->_validateResourceSetAndGetWrapper($resourceSet);
187
-			if (!is_null($resourceSetWrapper)) {
188
-				$resourceSetWrappers[] = $resourceSetWrapper;
189
-			}
190
-		}
191
-
192
-		return $resourceSetWrappers;
193
-	}
194
-
195
-	/**
196
-	 * To get all resource types in the data source,
197
-	 * Note: Wrapper for IMetadataProvider::getTypes method implementation
198
-	 *
199
-	 * @return ResourceType[]
200
-	 */
201
-	public function getTypes()
202
-	{
203
-		$resourceTypes = $this->metaProvider->getTypes();
204
-		$resourceTypeNames = array();
205
-		foreach ($resourceTypes as $resourceType) {
206
-			if (in_array($resourceType->getName(), $resourceTypeNames)) {
207
-				throw new ODataException(
208
-					Messages::providersWrapperEntityTypeNameShouldBeUnique($resourceType->getName()),
209
-					500
210
-				);
211
-			}
212
-
213
-			$resourceTypeNames[] = $resourceType->getName();
214
-			$this->_validateResourceType($resourceType);
215
-		}
216
-
217
-		return $resourceTypes;
218
-	}
219
-
220
-	/**
221
-	 * To get a resource set based on the specified resource set name which is
222
-	 * visible,
223
-	 * Note: Wrapper for IMetadataProvider::resolveResourceSet method
224
-	 * implementation
225
-	 *
226
-	 * @param string $name Name of the resource set
227
-	 *
228
-	 * @return ResourceSetWrapper|null Returns resource set with the given name if found, NULL if resource set is set to invisible or not found
229
-	 *
230
-	 */
231
-	public function resolveResourceSet($name)
232
-	{
233
-		if (array_key_exists($name, $this->setWrapperCache)) {
234
-			return $this->setWrapperCache[$name];
235
-		}
236
-
237
-		$resourceSet = $this->metaProvider->resolveResourceSet($name);
238
-		if (is_null($resourceSet)) {
239
-			return null;
240
-		}
241
-
242
-		return $this->_validateResourceSetAndGetWrapper($resourceSet);
243
-	}
244
-
245
-	/**
246
-	 * To get a resource type based on the resource set name,
247
-	 * Note: Wrapper for IMetadataProvider::resolveResourceType
248
-	 * method implementation
249
-	 *
250
-	 * @param string $name Name of the resource set
251
-	 *
252
-	 * @return ResourceType|null resource type with the given resource set name if found else NULL
253
-	 *
254
-	 *
255
-	 * @throws ODataException If the ResourceType is invalid
256
-	 */
257
-	public function resolveResourceType($name)
258
-	{
259
-		$resourceType = $this->metaProvider->resolveResourceType($name);
260
-		if (is_null($resourceType)) {
261
-			return null;
262
-		}
263
-
264
-		return $this->_validateResourceType($resourceType);
265
-	}
266
-
267
-	/**
268
-	 * The method must return a collection of all the types derived from
269
-	 * $resourceType The collection returned should NOT include the type
270
-	 * passed in as a parameter
271
-	 * Note: Wrapper for IMetadataProvider::getDerivedTypes
272
-	 * method implementation
273
-	 *
274
-	 * @param ResourceType $resourceType Resource to get derived resource types from
275
-	 *
276
-	 * @return ResourceType[]
277
-	 *
278
-	 * @throws InvalidOperationException when the meat provider doesn't return an array
279
-	 */
280
-	public function getDerivedTypes(ResourceType $resourceType)
281
-	{
282
-		$derivedTypes = $this->metaProvider->getDerivedTypes($resourceType);
283
-		if (!is_array($derivedTypes)) {
284
-			throw new InvalidOperationException(Messages::metadataAssociationTypeSetInvalidGetDerivedTypesReturnType($resourceType->getName()));
285
-		}
286
-
287
-		foreach ($derivedTypes as $derivedType) {
288
-			$this->_validateResourceType($derivedType);
289
-		}
290
-
291
-		return $derivedTypes;
292
-	}
293
-
294
-	/**
295
-	 * Returns true if $resourceType represents an Entity Type which has derived
296
-	 * Entity Types, else false.
297
-	 * Note: Wrapper for IMetadataProvider::hasDerivedTypes method
298
-	 * implementation
299
-	 *
300
-	 * @param ResourceType $resourceType Resource to check for derived resource
301
-	 *                                   types.
302
-	 *
303
-	 * @return boolean
304
-	 *
305
-	 * @throws ODataException If the ResourceType is invalid
306
-	 */
307
-	public function hasDerivedTypes(ResourceType $resourceType)
308
-	{
309
-		$this->_validateResourceType($resourceType);
310
-		return $this->metaProvider->hasDerivedTypes($resourceType);
311
-	}
312
-
313
-	/**
314
-	 * Gets the ResourceAssociationSet instance for the given source association end,
315
-	 * Note: Wrapper for IMetadataProvider::getResourceAssociationSet
316
-	 * method implementation
317
-	 *
318
-	 * @param ResourceSet $set Resource set of the source association end
319
-	 * @param ResourceType       $type       Resource type of the source association end
320
-	 * @param ResourceProperty   $property   Resource property of the source association end
321
-	 *
322
-	 *
323
-	 * @return ResourceAssociationSet|null Returns ResourceAssociationSet for the source
324
-	 *                                             association end, NULL if no such
325
-	 *                                             association end or resource set in the
326
-	 *                                             other end of the association is invisible
327
-	 */
328
-	public function getResourceAssociationSet(
329
-		ResourceSet $set,
330
-		ResourceType $type,
331
-		ResourceProperty $property
332
-	) {
333
-		$type = $this->_getResourceTypeWherePropertyIsDeclared($type, $property);
334
-		$cacheKey = $set->getName() . '_' . $type->getName() . '_' . $property->getName();
335
-
336
-		if (array_key_exists($cacheKey, $this->associationSetCache)) {
337
-			return $this->associationSetCache[$cacheKey];
338
-		}
339
-
340
-		$associationSet = $this->metaProvider->getResourceAssociationSet(
341
-			$set,
342
-			$type,
343
-			$property
344
-		);
345
-
346
-		if (!is_null($associationSet)) {
347
-			$thisAssociationSetEnd = $associationSet->getResourceAssociationSetEnd(
348
-				$set,
349
-				$type,
350
-				$property
351
-			);
352
-
353
-			$relatedAssociationSetEnd = $associationSet->getRelatedResourceAssociationSetEnd(
354
-				$set,
355
-				$type,
356
-				$property
357
-			);
358
-
359
-			//If $thisAssociationSetEnd or $relatedAssociationSetEnd
360
-			//is null means the associationset
361
-			//we got from the IDSMP::getResourceAssociationSet is invalid.
362
-			//AssociationSet::getResourceAssociationSetEnd
363
-			//return null, if AssociationSet's End1 or End2's resourceset name
364
-			//is not matching with the name of
365
-			//resource set wrapper (param1) and resource type is not assignable
366
-			//from given resource type (param2)
367
-			if (is_null($thisAssociationSetEnd) || is_null($relatedAssociationSetEnd)) {
368
-				throw new ODataException(
369
-					Messages::providersWrapperIDSMPGetResourceSetReturnsInvalidResourceSet(
370
-						$set->getName(),
371
-						$type->getFullName(),
372
-						$property->getName()
373
-					),
374
-					500
375
-				);
376
-			}
377
-
378
-			$relatedResourceSetWrapper = $this->_validateResourceSetAndGetWrapper(
379
-				$relatedAssociationSetEnd->getResourceSet()
380
-			);
381
-			if ($relatedResourceSetWrapper === null) {
382
-				$associationSet = null;
383
-			} else {
384
-				$this->_validateResourceType($thisAssociationSetEnd->getResourceType());
385
-				$this->_validateResourceType($relatedAssociationSetEnd->getResourceType());
386
-			}
387
-		}
388
-
389
-		$this->associationSetCache[$cacheKey] = $associationSet;
390
-		return $associationSet;
391
-	}
392
-
393
-	/**
394
-	 * Gets the target resource set wrapper for the given navigation property,
395
-	 * source resource set wrapper and the source resource type
396
-	 *
397
-	 * @param ResourceSetWrapper $resourceSetWrapper         Source resource set.
398
-	 * @param ResourceType       $resourceType               Source resource type.
399
-	 * @param ResourceProperty   $navigationResourceProperty Navigation property.
400
-	 *
401
-	 * @return ResourceSetWrapper|null Returns instance of ResourceSetWrapper
402
-	 *     (describes the entity set and associated configuration) for the
403
-	 *     given navigation property. returns NULL if resourceset for the
404
-	 *     navigation property is invisible or if metadata provider returns
405
-	 *     null resource association set
406
-	 */
407
-	public function getResourceSetWrapperForNavigationProperty(
408
-		ResourceSetWrapper $resourceSetWrapper,
409
-		ResourceType $resourceType,
410
-		ResourceProperty $navigationResourceProperty
411
-	) {
412
-		$associationSet = $this->getResourceAssociationSet(
413
-			$resourceSetWrapper,
414
-			$resourceType,
415
-			$navigationResourceProperty
416
-		);
417
-
418
-		if (!is_null($associationSet)) {
419
-			$relatedAssociationSetEnd = $associationSet->getRelatedResourceAssociationSetEnd(
420
-				$resourceSetWrapper->getResourceSet(),
421
-				$resourceType,
422
-				$navigationResourceProperty
423
-			);
424
-			return $this->_validateResourceSetAndGetWrapper(
425
-				$relatedAssociationSetEnd->getResourceSet()
426
-			);
427
-		}
428
-
429
-		return null;
430
-	}
431
-
432
-	/**
433
-	 * Gets the visible resource properties for the given resource type from the given resource set wrapper.
434
-	 *
435
-	 * @param ResourceSetWrapper $setWrapper Resource set wrapper in question.
436
-	 * @param ResourceType       $resourceType       Resource type in question.
437
-	 * @return ResourceProperty[] Collection of visible resource properties from the given resource set wrapper and resource type.
438
-	 */
439
-	public function getResourceProperties(ResourceSetWrapper $setWrapper, ResourceType $resourceType) {
440
-		if ($resourceType->getResourceTypeKind() != ResourceTypeKind::ENTITY) {
441
-			//Complex resource type
442
-			return $resourceType->getAllProperties();
443
-		}
444
-		//TODO: move this to doctrine annotations
445
-		$cacheKey = $setWrapper->getName() . '_' . $resourceType->getFullName();
446
-		if (!array_key_exists($cacheKey, $this->propertyCache)) {
447
-			//Fill the cache
448
-			$this->propertyCache[$cacheKey] = array();
449
-			foreach ($resourceType->getAllProperties() as $resourceProperty) {
450
-				//Check whether this is a visible navigation property
451
-				//TODO: is this broken?? see #87
452
-				if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY
453
-					&& !is_null($this->getResourceSetWrapperForNavigationProperty($setWrapper, $resourceType, $resourceProperty))
454
-				) {
455
-					$this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty;
456
-				} else {
457
-					//primitive, bag or complex property
458
-					$this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty;
459
-				}
460
-			}
461
-		}
462
-		return $this->propertyCache[$cacheKey];
463
-
464
-	}
465
-
466
-	/**
467
-	 * Wrapper function over _validateResourceSetAndGetWrapper function
468
-	 *
469
-	 * @param ResourceSet $resourceSet see the comments of _validateResourceSetAndGetWrapper
470
-	 *
471
-	 * @return ResourceSetWrapper|null see the comments of _validateResourceSetAndGetWrapper
472
-	 */
473
-	public function validateResourceSetAndGetWrapper(ResourceSet $resourceSet)
474
-	{
475
-		return $this->_validateResourceSetAndGetWrapper($resourceSet);
476
-	}
477
-
478
-	/**
479
-	 * Gets the Edm Schema version compliance to the metadata
480
-	 *
481
-	 * @return EdmSchemaVersion
482
-	 */
483
-	public function getEdmSchemaVersion()
484
-	{
485
-		//The minimal schema version for custom provider is 1.1
486
-		return EdmSchemaVersion::VERSION_1_DOT_1;
487
-	}
488
-
489
-	/**
490
-	 * This function perform the following operations
491
-	 *  (1) If the cache contain an entry [key, value] for the resourceset then
492
-	 *      return the entry-value
493
-	 *  (2) If the cache not contain an entry for the resourceset then validate
494
-	 *      the resourceset
495
-	 *            (a) If valid add entry as [resouceset_name, resourceSetWrapper]
496
-	 *            (b) if not valid add entry as [resouceset_name, null]
497
-	 *  Note: validating a resourceset means checking the resourceset is visible
498
-	 *  or not using configuration
499
-	 *
500
-	 * @param ResourceSet $resourceSet The resourceset to validate and get the
501
-	 *                                 wrapper for
502
-	 *
503
-	 * @return ResourceSetWrapper|null Returns an instance if a resource set with the given name is visible
504
-	 */
505
-	private function _validateResourceSetAndGetWrapper(ResourceSet $resourceSet)
506
-	{
507
-		$cacheKey = $resourceSet->getName();
508
-		if (array_key_exists($cacheKey, $this->setWrapperCache)) {
509
-			return $this->setWrapperCache[$cacheKey];
510
-		}
511
-
512
-		$this->_validateResourceType($resourceSet->getResourceType());
513
-		$wrapper = new ResourceSetWrapper($resourceSet, $this->config);
514
-		if ($wrapper->isVisible()) {
515
-			$this->setWrapperCache[$cacheKey] = $wrapper;
516
-		} else {
517
-			$this->setWrapperCache[$cacheKey] = null;
518
-		}
519
-
520
-		return $this->setWrapperCache[$cacheKey];
521
-	}
522
-
523
-	/**
524
-	 * Validates the given instance of ResourceType
525
-	 *
526
-	 * @param ResourceType $resourceType The ResourceType to validate
527
-	 *
528
-	 * @return ResourceType
529
-	 *
530
-	 * @throws ODataException Exception if $resourceType is invalid
531
-	 */
532
-	private function _validateResourceType(ResourceType $resourceType)
533
-	{
534
-		$cacheKey = $resourceType->getName();
535
-		if (array_key_exists($cacheKey, $this->typeCache)) {
536
-			return $this->typeCache[$cacheKey];
537
-		}
538
-
539
-		//TODO: Do validation if any for the ResourceType
540
-		$this->typeCache[$cacheKey] = $resourceType;
541
-		return $resourceType;
542
-	}
543
-
544
-	/**
545
-	 * Gets the resource type on which the resource property is declared on,
546
-	 * If property is not declared in the given resource type, then this
547
-	 * function drill down to the inheritance hierarchy of the given resource
548
-	 * type to find out the base class in which the property is declared
549
-	 *
550
-	 * @param ResourceType     $resourceType     The resource type to start looking
551
-	 * @param ResourceProperty $resourceProperty The resource property in question
552
-	 *
553
-	 * @return ResourceType|null Returns reference to the ResourceType on which
554
-	 *                                   the $resourceProperty is declared, NULL if
555
-	 *                                   $resourceProperty is not declared anywhere
556
-	 *                                   in the inheritance hierarchy
557
-	 */
558
-	private function _getResourceTypeWherePropertyIsDeclared(ResourceType $resourceType,
559
-		ResourceProperty $resourceProperty
560
-	) {
561
-		$type = $resourceType;
562
-		while ($type !== null) {
563
-			if ($type->resolvePropertyDeclaredOnThisType($resourceProperty->getName()) !== null) {
564
-				break;
565
-			}
566
-
567
-			$type = $type->getBaseType();
568
-		}
569
-
570
-		return $type;
571
-	}
572
-
573
-	/**
574
-	 * Gets the underlying custom expression provider, the end developer is
575
-	 * responsible for implementing IExpressionProvider if he choose for
576
-	 *
577
-	 * @return IExpressionProvider Instance of IExpressionProvider implementation.
578
-	 *
579
-	 */
580
-	public function getExpressionProvider()
581
-	{
582
-		$expressionProvider = $this->queryProvider->getExpressionProvider();
583
-		if (is_null($expressionProvider)) {
584
-			throw ODataException::createInternalServerError(Messages::providersWrapperExpressionProviderMustNotBeNullOrEmpty());
585
-		}
586
-
587
-		if (!$expressionProvider instanceof IExpressionProvider)
588
-		{
589
-			throw ODataException::createInternalServerError(Messages::providersWrapperInvalidExpressionProviderInstance());
590
-		}
591
-
592
-		return $expressionProvider;
593
-	}
594
-
595
-	/**
596
-	 * Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters
597
-	 * If the query provider can not handle ordered paging, it must return the entire result set and POData will
598
-	 * perform the ordering and paging
599
-	 *
600
-	 * @return Boolean True if the query provider can handle ordered paging, false if POData should perform the paging
601
-	 */
602
-	public function handlesOrderedPaging()
603
-	{
604
-		return $this->queryProvider->handlesOrderedPaging();
605
-	}
606
-
607
-
608
-	/**
609
-	 * @param QueryResult $queryResult
610
-	 * @param string $methodName
611
-	 */
612
-	private function ValidateQueryResult($queryResult, QueryType $queryType, $methodName){
613
-		if (!$queryResult instanceof QueryResult) {
614
-			throw ODataException::createInternalServerError(
615
-				Messages::queryProviderReturnsNonQueryResult($methodName)
616
-			);
617
-		}
618
-
619
-		if($queryType == QueryType::COUNT() || $queryType == QueryType::ENTITIES_WITH_COUNT()){
620
-			//and the provider is supposed to handle the ordered paging they must return a count!
621
-			if($this->queryProvider->handlesOrderedPaging() && !is_numeric($queryResult->count)){
622
-				throw ODataException::createInternalServerError(
623
-					Messages::queryProviderResultCountMissing($methodName, $queryType)
624
-				);
625
-			}
626
-
627
-			//If POData is supposed to handle the ordered aging they must return results! (possibly empty)
628
-			if(!$this->queryProvider->handlesOrderedPaging() && !is_array($queryResult->results)){
629
-				throw ODataException::createInternalServerError(
630
-					Messages::queryProviderResultsMissing($methodName, $queryType)
631
-				);
632
-			}
633
-		}
634
-
635
-		if(($queryType == QueryType::ENTITIES() || $queryType == QueryType::ENTITIES_WITH_COUNT()) && !is_array($queryResult->results)){
636
-			throw ODataException::createInternalServerError(
637
-				Messages::queryProviderResultsMissing($methodName, $queryType)
638
-			);
639
-		}
640
-	}
641
-
642
-	/**
643
-	 * Gets collection of entities belongs to an entity set
644
-	 *
645
-	 * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
646
-	 * @param ResourceSet $resourceSet The entity set containing the entities that need to be fetched
647
-	 * @param FilterInfo $filterInfo represents the $filter parameter of the OData query.  NULL if no $filter specified
648
-	 * @param InternalOrderByInfo $orderBy The orderBy information
649
-	 * @param int $top The top count
650
-	 * @param int $skip The skip count
651
-	 * @param \POData\UriProcessor\QueryProcessor\SkipTokenParser\SkipTokenInfo $skiptoken
652
-	 * @param \POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ExpandedProjectionNode[] $expansion
653
-	 *
654
-	 * @return QueryResult
655
-	 */
656
-	public function getResourceSet(QueryType $queryType, ResourceSet $resourceSet, $filterInfo, $orderBy, $top, $skip, $skiptoken = null, $expansion = null)
657
-	{
658
-
659
-		$queryResult = $this->queryProvider->getResourceSet(
660
-			$queryType,
661
-			$resourceSet,
662
-			$filterInfo,
663
-			$orderBy,
664
-			$top,
665
-			$skip,
666
-			$skiptoken,
667
-			$expansion
668
-		);
669
-
670
-		$this->validateQueryResult($queryResult, $queryType, 'IQueryProvider::getResourceSet');
671
-
672
-		return $queryResult;
673
-	}
674
-
675
-
676
-
677
-	/**
678
-	 * Gets an entity instance from an entity set identified by a key
679
-	 *
680
-	 * @param ResourceSet $resourceSet The entity set containing the entity to fetch
681
-	 * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
682
-	 *
683
-	 * @return object|null Returns entity instance if found else null
684
-	 */
685
-	public function getResourceFromResourceSet(ResourceSet $resourceSet, KeyDescriptor $keyDescriptor)
686
-	{
687
-		$entityInstance = $this->queryProvider->getResourceFromResourceSet($resourceSet, $keyDescriptor);
688
-		$this->_validateEntityInstance(
689
-			$entityInstance,
690
-			$resourceSet,
691
-			$keyDescriptor,
692
-			'IQueryProvider::getResourceFromResourceSet'
693
-		);
694
-		return $entityInstance;
695
-	}
696
-
697
-	/**
698
-	 * Puts an entity instance to entity set identified by a key
699
-	 *
700
-	 * @param ResourceSet $resourceSet The entity set containing the entity to update
701
-	 * @param KeyDescriptor $keyDescriptor The key identifying the entity to update
702
-	 *
703
-	 * @return bool|null Returns result of executiong query
704
-	 */
705
-	public function putResource(
706
-		ResourceSet $resourceSet,
707
-		KeyDescriptor $keyDescriptor,
708
-		$data
709
-	) {
710
-		$queryResult = $this->queryProvider->putResource(
711
-			$resourceSet,
712
-			$keyDescriptor,
713
-			$data
714
-		);
715
-
716
-		return $queryResult;
717
-	}
718
-
719
-	/**
720
-	 * Posts an entity instance to entity set identified by a key
721
-	 *
722
-	 * @param ResourceSet $resourceSet The entity set containing the entity to update
723
-	 *
724
-	 * @return bool|null Returns result of executiong query
725
-	 */
726
-	public function postResource(
727
-		ResourceSet $resourceSet,
728
-		$data
729
-	) {
730
-		$queryResult = $this->queryProvider->postResource(
731
-			$resourceSet,
732
-			$data
733
-		);
734
-
735
-		return $queryResult;
736
-	}
737
-
738
-	/**
739
-	 * Posts an entity instance to entity set identified by a key
740
-	 *
741
-	 * @param ResourceSet $resourceSet The entity set containing the entity to update
742
-	 * @param KeyDescriptor $keyDescriptor The key identifying the entity to update
743
-	 *
744
-	 * @return bool|null Returns result of executiong query
745
-	 */
746
-	public function deleteResource(
747
-		ResourceSet $resourceSet,
748
-		$keyDescriptor
749
-	) {
750
-		$queryResult = $this->queryProvider->deleteResource(
751
-			$resourceSet,
752
-			$keyDescriptor
753
-		);
754
-
755
-		return $queryResult;
756
-	}
757
-
758
-	/**
759
-	 * Get related resource set for a resource
760
-	 *
761
-	 * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
762
-	 * @param ResourceSet $sourceResourceSet The entity set containing the source entity
763
-	 * @param object $sourceEntity The source entity instance.
764
-	 * @param ResourceSet      $targetResourceSet    The resource set of containing the target of the navigation property
765
-	 * @param ResourceProperty $targetProperty       The navigation property to retrieve
766
-	 * @param FilterInfo  $filterInfo represents the $filter parameter of the OData query.  NULL if no $filter specified
767
-	 * @param mixed $orderBy sorted order if we want to get the data in some specific order
768
-	 * @param int $top number of records which  need to be skip
769
-	 * @param String $skip value indicating what records to skip
770
-	 *
771
-	 * @return QueryResult
772
-	 *
773
-	 * @throws ODataException
774
-	 */
775
-	public function getRelatedResourceSet(
776
-		QueryType $queryType,
777
-		ResourceSet $sourceResourceSet,
778
-		$sourceEntity,
779
-		ResourceSet $targetResourceSet,
780
-		ResourceProperty $targetProperty,
781
-		$filterInfo,
782
-		$orderBy,
783
-		$top,
784
-		$skip
785
-	) {
786
-
787
-		$queryResult = $this->queryProvider->getRelatedResourceSet(
788
-			$queryType,
789
-			$sourceResourceSet,
790
-			$sourceEntity,
791
-			$targetResourceSet,
792
-			$targetProperty,
793
-			$filterInfo,
794
-			$orderBy,
795
-			$top,
796
-			$skip
797
-		);
798
-
799
-
800
-		$this->validateQueryResult($queryResult, $queryType, 'IQueryProvider::getRelatedResourceSet');
801
-
802
-
803
-		return $queryResult;
804
-	}
805
-
806
-	/**
807
-	 * Gets a related entity instance from an entity set identified by a key
808
-	 *
809
-	 * @param ResourceSet      $sourceResourceSet The entity set related to the entity to be fetched.
810
-	 * @param object           $sourceEntity      The related entity instance.
811
-	 * @param ResourceSet      $targetResourceSet The entity set from which entity needs to be fetched.
812
-	 * @param ResourceProperty $targetProperty    The metadata of the target property.
813
-	 * @param KeyDescriptor    $keyDescriptor     The key to identify the entity to be fetched.
814
-	 *
815
-	 *
816
-	 * @return object|null Returns entity instance if found else null
817
-	 */
818
-	public function getResourceFromRelatedResourceSet(ResourceSet $sourceResourceSet,
819
-		$sourceEntity, ResourceSet $targetResourceSet, ResourceProperty $targetProperty,
820
-		KeyDescriptor $keyDescriptor
821
-	) {
822
-		$entityInstance = $this->queryProvider->getResourceFromRelatedResourceSet(
823
-			$sourceResourceSet,
824
-			$sourceEntity,
825
-			$targetResourceSet,
826
-			$targetProperty,
827
-			$keyDescriptor
828
-		);
829
-
830
-		$this->_validateEntityInstance(
831
-			$entityInstance, $targetResourceSet,
832
-			$keyDescriptor,
833
-			'IQueryProvider::getResourceFromRelatedResourceSet'
834
-		);
835
-		return $entityInstance;
836
-	}
837
-
838
-	/**
839
-	 * Get related resource for a resource
840
-	 *
841
-	 * @param ResourceSet      $sourceResourceSet The source resource set
842
-	 * @param object           $sourceEntity      The source resource
843
-	 * @param ResourceSet      $targetResourceSet The resource set of the navigation
844
-	 *                                            property
845
-	 * @param ResourceProperty $targetProperty    The navigation property to be
846
-	 *                                            retrieved
847
-	 *
848
-	 * @return object|null The related resource if exists else null
849
-	 */
850
-	public function getRelatedResourceReference(ResourceSet $sourceResourceSet,
851
-		$sourceEntity, ResourceSet $targetResourceSet,
852
-		ResourceProperty $targetProperty
853
-	) {
854
-		$entityInstance = $this->queryProvider->getRelatedResourceReference(
855
-			$sourceResourceSet,
856
-			$sourceEntity,
857
-			$targetResourceSet,
858
-			$targetProperty
859
-		);
860
-
861
-		// we will not throw error if the resource reference is null
862
-		// e.g. Orders(1234)/Customer => Customer can be null, this is
863
-		// allowed if Customer is last segment. consider the following:
864
-		// Orders(1234)/Customer/Orders => here if Customer is null then
865
-		// the UriProcessor will throw error.
866
-		if (!is_null($entityInstance)) {
867
-			$entityName
868
-				= $targetResourceSet
869
-					->getResourceType()
870
-					->getInstanceType()
871
-					->getName();
872
-			if (!is_object($entityInstance)
873
-				|| !($entityInstance instanceof $entityName)
874
-			) {
875
-				throw ODataException::createInternalServerError(
876
-					Messages::providersWrapperIDSQPMethodReturnsUnExpectedType(
877
-						$entityName,
878
-						'IQueryProvider::getRelatedResourceReference'
879
-					)
880
-				);
881
-			}
882
-
883
-			foreach ($targetProperty->getResourceType()->getKeyProperties()
884
-			as $keyName => $resourceProperty) {
885
-				try {
886
-					$keyProperty = new \ReflectionProperty(
887
-						$entityInstance,
888
-						$keyName
889
-					);
890
-					$keyProperty->setAccessible(true);
891
-					$keyValue = $keyProperty->getValue($entityInstance);
892
-					if (is_null($keyValue)) {
893
-						throw ODataException::createInternalServerError(
894
-							Messages::providersWrapperIDSQPMethodReturnsInstanceWithNullKeyProperties('IDSQP::getRelatedResourceReference')
895
-						);
896
-					}
897
-				} catch (\ReflectionException $reflectionException) {
898
-					//throw ODataException::createInternalServerError(
899
-					//    Messages::orderByParserFailedToAccessOrInitializeProperty(
900
-					//        $resourceProperty->getName(), $resourceType->getName()
901
-					//    )
902
-					//);
903
-				}
904
-			}
905
-		}
906
-
907
-		return $entityInstance;
908
-	}
909
-
910
-	/**
911
-	 * Validate the given entity instance.
912
-	 *
913
-	 * @param object        $entityInstance Entity instance to validate
914
-	 * @param ResourceSet   &$resourceSet   Resource set to which the entity
915
-	 *                                      instance belongs to.
916
-	 * @param KeyDescriptor &$keyDescriptor The key descriptor.
917
-	 * @param string        $methodName     Method from which this function
918
-	 *                                      invoked.
919
-	 *
920
-	 * @return void
921
-	 *
922
-	 * @throws ODataException
923
-	 */
924
-	private function _validateEntityInstance($entityInstance,
925
-		ResourceSet &$resourceSet,
926
-		KeyDescriptor &$keyDescriptor,
927
-		$methodName
928
-	) {
929
-		if (is_null($entityInstance)) {
930
-			throw ODataException::createResourceNotFoundError($resourceSet->getName());
931
-		}
932
-
933
-		$entityName = $resourceSet->getResourceType()->getInstanceType()->getName();
934
-		if (!is_object($entityInstance)
935
-			|| !($entityInstance instanceof $entityName)
936
-		) {
937
-			throw ODataException::createInternalServerError(
938
-				Messages::providersWrapperIDSQPMethodReturnsUnExpectedType(
939
-					$entityName,
940
-					$methodName
941
-				)
942
-			);
943
-		}
944
-
945
-		foreach ($keyDescriptor->getValidatedNamedValues()
946
-			as $keyName => $valueDescription) {
947
-			try {
948
-				$keyProperty = new \ReflectionProperty($entityInstance, $keyName);
949
-				$keyProperty->setAccessible(true);
950
-				$keyValue = $keyProperty->getValue($entityInstance);
951
-				if (is_null($keyValue)) {
952
-					throw ODataException::createInternalServerError(
953
-						Messages::providersWrapperIDSQPMethodReturnsInstanceWithNullKeyProperties($methodName)
954
-					);
955
-				}
956
-
957
-				$convertedValue
958
-					= $valueDescription[1]->convert($valueDescription[0]);
959
-				if ($keyValue != $convertedValue) {
960
-					throw ODataException::createInternalServerError(
961
-						Messages::providersWrapperIDSQPMethodReturnsInstanceWithNonMatchingKeys($methodName)
962
-					);
963
-				}
964
-			} catch (\ReflectionException $reflectionException) {
965
-				//throw ODataException::createInternalServerError(
966
-				//  Messages::orderByParserFailedToAccessOrInitializeProperty(
967
-				//      $resourceProperty->getName(), $resourceType->getName()
968
-				//  )
969
-				//);
970
-			}
971
-		}
972
-	}
973
-
974
-	/**
975
-	 * Assert that the given condition is true.
976
-	 *
977
-	 * @param boolean $condition         Condition to be asserted.
978
-	 * @param string  $conditionAsString String containing message incase
979
-	 *                                   if assertion fails.
980
-	 *
981
-	 * @throws InvalidOperationException Incase if assertion fails.
982
-	 *
983
-	 * @return void
984
-	 */
985
-	protected function assert($condition, $conditionAsString)
986
-	{
987
-		if (!$condition) {
988
-			throw new InvalidOperationException("Unexpected state, expecting $conditionAsString");
989
-		}
990
-	}
35
+    /**
36
+     * Holds reference to IMetadataProvider implementation
37
+     *
38
+     * @var IMetadataProvider
39
+     */
40
+    private $metaProvider;
41
+
42
+    /**
43
+     * Holds reference to IQueryProvider implementation
44
+     *
45
+     * @var IQueryProvider
46
+     *
47
+     */
48
+    private $queryProvider;
49
+
50
+    /**
51
+     * Holds reference to IServiceConfiguration implementation
52
+     *
53
+     * @var ServiceConfiguration
54
+     */
55
+    private $config;
56
+
57
+
58
+    /**
59
+     * Cache for ResourceProperties of a resource type that belongs to a
60
+     * resource set. An entry (ResourceProperty collection) in this cache
61
+     * contains only the visible properties of ResourceType.
62
+     *
63
+     * @var array(string, array(string, ResourceProperty))
64
+     */
65
+    private $propertyCache;
66
+
67
+    /**
68
+     * Cache for ResourceSetWrappers. If ResourceSet is invisible value will
69
+     * be null.
70
+     *
71
+     * @var ResourceSetWrapper[] indexed by resource set name
72
+     */
73
+    private $setWrapperCache;
74
+
75
+    /**
76
+     * Cache for ResourceTypes
77
+     *
78
+     * @var ResourceType[] indexed by resource type name
79
+     */
80
+    private $typeCache;
81
+
82
+    /**
83
+     * Cache for ResourceAssociationSet. If ResourceAssociationSet is invisible
84
+     * value will be null.
85
+     *
86
+     * @var ResourceAssociationSet[] indexed by name
87
+     */
88
+    private $associationSetCache;
89
+
90
+    /**
91
+     * Creates a new instance of ProvidersWrapper
92
+     *
93
+     * @param IMetadataProvider $metadataProvider Reference to IMetadataProvider implementation
94
+     * @param IQueryProvider    $queryProvider    Reference to IQueryProvider implementation
95
+     * @param ServiceConfiguration    $configuration    Reference to IServiceConfiguration implementation
96
+     */
97
+    public function __construct(IMetadataProvider $metadataProvider, IQueryProvider $queryProvider, ServiceConfiguration $configuration)
98
+    {
99
+        $this->metaProvider = $metadataProvider;
100
+        $this->queryProvider = $queryProvider;
101
+        $this->config = $configuration;
102
+        $this->setWrapperCache = array();
103
+        $this->typeCache = array();
104
+        $this->associationSetCache = array();
105
+        $this->propertyCache = array();
106
+    }
107
+
108
+    //Wrappers for IMetadataProvider methods
109
+
110
+    /**
111
+     * To get the Container name for the data source,
112
+     * Note: Wrapper for IMetadataProvider::getContainerName method
113
+     * implementation
114
+     *
115
+     * @return string that contains the name of the container
116
+     *
117
+     * @throws ODataException Exception if implementation returns empty container name
118
+     *
119
+     */
120
+    public function getContainerName()
121
+    {
122
+        $containerName = $this->metaProvider->getContainerName();
123
+        if (empty($containerName)) {
124
+            throw new ODataException(
125
+                Messages::providersWrapperContainerNameMustNotBeNullOrEmpty(),
126
+                500
127
+            );
128
+        }
129
+
130
+        return $containerName;
131
+    }
132
+
133
+    /**
134
+     * To get Namespace name for the data source,
135
+     * Note: Wrapper for IMetadataProvider::getContainerNamespace method implementation
136
+     *
137
+     * @return string that contains the namespace name.
138
+     *
139
+     * @throws ODataException Exception if implementation returns empty container namespace
140
+     *
141
+     */
142
+    public function getContainerNamespace()
143
+    {
144
+        $containerNamespace = $this->metaProvider->getContainerNamespace();
145
+        if (empty($containerNamespace)) {
146
+            throw new ODataException(
147
+                Messages::providersWrapperContainerNamespaceMustNotBeNullOrEmpty(),
148
+                500
149
+            );
150
+        }
151
+
152
+        return $containerNamespace;
153
+    }
154
+
155
+    /**
156
+     * To get the data service configuration
157
+     *
158
+     * @return ServiceConfiguration
159
+     */
160
+    public function getConfiguration()
161
+    {
162
+        return $this->config;
163
+    }
164
+
165
+    /**
166
+     *  To get all entity set information,
167
+     *  Note: Wrapper for IMetadataProvider::getResourceSets method implementation,
168
+     *  This method returns array of ResourceSetWrapper instances but the corresponding IDSMP method returns array of ResourceSet instances
169
+     *
170
+     *  @return ResourceSetWrapper[] The ResourceSetWrappers for the visible ResourceSets
171
+     *  @throws ODataException when two resource sets with the same name are encountered
172
+     *
173
+     */
174
+    public function getResourceSets()
175
+    {
176
+        $resourceSets = $this->metaProvider->getResourceSets();
177
+        $resourceSetWrappers = array();
178
+        $resourceSetNames = array();
179
+        foreach ($resourceSets as $resourceSet) {
180
+            $name = $resourceSet->getName();
181
+            if (in_array($name, $resourceSetNames)) {
182
+                throw new ODataException(Messages::providersWrapperEntitySetNameShouldBeUnique($name), 500);
183
+            }
184
+
185
+            $resourceSetNames[] = $name;
186
+            $resourceSetWrapper = $this->_validateResourceSetAndGetWrapper($resourceSet);
187
+            if (!is_null($resourceSetWrapper)) {
188
+                $resourceSetWrappers[] = $resourceSetWrapper;
189
+            }
190
+        }
191
+
192
+        return $resourceSetWrappers;
193
+    }
194
+
195
+    /**
196
+     * To get all resource types in the data source,
197
+     * Note: Wrapper for IMetadataProvider::getTypes method implementation
198
+     *
199
+     * @return ResourceType[]
200
+     */
201
+    public function getTypes()
202
+    {
203
+        $resourceTypes = $this->metaProvider->getTypes();
204
+        $resourceTypeNames = array();
205
+        foreach ($resourceTypes as $resourceType) {
206
+            if (in_array($resourceType->getName(), $resourceTypeNames)) {
207
+                throw new ODataException(
208
+                    Messages::providersWrapperEntityTypeNameShouldBeUnique($resourceType->getName()),
209
+                    500
210
+                );
211
+            }
212
+
213
+            $resourceTypeNames[] = $resourceType->getName();
214
+            $this->_validateResourceType($resourceType);
215
+        }
216
+
217
+        return $resourceTypes;
218
+    }
219
+
220
+    /**
221
+     * To get a resource set based on the specified resource set name which is
222
+     * visible,
223
+     * Note: Wrapper for IMetadataProvider::resolveResourceSet method
224
+     * implementation
225
+     *
226
+     * @param string $name Name of the resource set
227
+     *
228
+     * @return ResourceSetWrapper|null Returns resource set with the given name if found, NULL if resource set is set to invisible or not found
229
+     *
230
+     */
231
+    public function resolveResourceSet($name)
232
+    {
233
+        if (array_key_exists($name, $this->setWrapperCache)) {
234
+            return $this->setWrapperCache[$name];
235
+        }
236
+
237
+        $resourceSet = $this->metaProvider->resolveResourceSet($name);
238
+        if (is_null($resourceSet)) {
239
+            return null;
240
+        }
241
+
242
+        return $this->_validateResourceSetAndGetWrapper($resourceSet);
243
+    }
244
+
245
+    /**
246
+     * To get a resource type based on the resource set name,
247
+     * Note: Wrapper for IMetadataProvider::resolveResourceType
248
+     * method implementation
249
+     *
250
+     * @param string $name Name of the resource set
251
+     *
252
+     * @return ResourceType|null resource type with the given resource set name if found else NULL
253
+     *
254
+     *
255
+     * @throws ODataException If the ResourceType is invalid
256
+     */
257
+    public function resolveResourceType($name)
258
+    {
259
+        $resourceType = $this->metaProvider->resolveResourceType($name);
260
+        if (is_null($resourceType)) {
261
+            return null;
262
+        }
263
+
264
+        return $this->_validateResourceType($resourceType);
265
+    }
266
+
267
+    /**
268
+     * The method must return a collection of all the types derived from
269
+     * $resourceType The collection returned should NOT include the type
270
+     * passed in as a parameter
271
+     * Note: Wrapper for IMetadataProvider::getDerivedTypes
272
+     * method implementation
273
+     *
274
+     * @param ResourceType $resourceType Resource to get derived resource types from
275
+     *
276
+     * @return ResourceType[]
277
+     *
278
+     * @throws InvalidOperationException when the meat provider doesn't return an array
279
+     */
280
+    public function getDerivedTypes(ResourceType $resourceType)
281
+    {
282
+        $derivedTypes = $this->metaProvider->getDerivedTypes($resourceType);
283
+        if (!is_array($derivedTypes)) {
284
+            throw new InvalidOperationException(Messages::metadataAssociationTypeSetInvalidGetDerivedTypesReturnType($resourceType->getName()));
285
+        }
286
+
287
+        foreach ($derivedTypes as $derivedType) {
288
+            $this->_validateResourceType($derivedType);
289
+        }
290
+
291
+        return $derivedTypes;
292
+    }
293
+
294
+    /**
295
+     * Returns true if $resourceType represents an Entity Type which has derived
296
+     * Entity Types, else false.
297
+     * Note: Wrapper for IMetadataProvider::hasDerivedTypes method
298
+     * implementation
299
+     *
300
+     * @param ResourceType $resourceType Resource to check for derived resource
301
+     *                                   types.
302
+     *
303
+     * @return boolean
304
+     *
305
+     * @throws ODataException If the ResourceType is invalid
306
+     */
307
+    public function hasDerivedTypes(ResourceType $resourceType)
308
+    {
309
+        $this->_validateResourceType($resourceType);
310
+        return $this->metaProvider->hasDerivedTypes($resourceType);
311
+    }
312
+
313
+    /**
314
+     * Gets the ResourceAssociationSet instance for the given source association end,
315
+     * Note: Wrapper for IMetadataProvider::getResourceAssociationSet
316
+     * method implementation
317
+     *
318
+     * @param ResourceSet $set Resource set of the source association end
319
+     * @param ResourceType       $type       Resource type of the source association end
320
+     * @param ResourceProperty   $property   Resource property of the source association end
321
+     *
322
+     *
323
+     * @return ResourceAssociationSet|null Returns ResourceAssociationSet for the source
324
+     *                                             association end, NULL if no such
325
+     *                                             association end or resource set in the
326
+     *                                             other end of the association is invisible
327
+     */
328
+    public function getResourceAssociationSet(
329
+        ResourceSet $set,
330
+        ResourceType $type,
331
+        ResourceProperty $property
332
+    ) {
333
+        $type = $this->_getResourceTypeWherePropertyIsDeclared($type, $property);
334
+        $cacheKey = $set->getName() . '_' . $type->getName() . '_' . $property->getName();
335
+
336
+        if (array_key_exists($cacheKey, $this->associationSetCache)) {
337
+            return $this->associationSetCache[$cacheKey];
338
+        }
339
+
340
+        $associationSet = $this->metaProvider->getResourceAssociationSet(
341
+            $set,
342
+            $type,
343
+            $property
344
+        );
345
+
346
+        if (!is_null($associationSet)) {
347
+            $thisAssociationSetEnd = $associationSet->getResourceAssociationSetEnd(
348
+                $set,
349
+                $type,
350
+                $property
351
+            );
352
+
353
+            $relatedAssociationSetEnd = $associationSet->getRelatedResourceAssociationSetEnd(
354
+                $set,
355
+                $type,
356
+                $property
357
+            );
358
+
359
+            //If $thisAssociationSetEnd or $relatedAssociationSetEnd
360
+            //is null means the associationset
361
+            //we got from the IDSMP::getResourceAssociationSet is invalid.
362
+            //AssociationSet::getResourceAssociationSetEnd
363
+            //return null, if AssociationSet's End1 or End2's resourceset name
364
+            //is not matching with the name of
365
+            //resource set wrapper (param1) and resource type is not assignable
366
+            //from given resource type (param2)
367
+            if (is_null($thisAssociationSetEnd) || is_null($relatedAssociationSetEnd)) {
368
+                throw new ODataException(
369
+                    Messages::providersWrapperIDSMPGetResourceSetReturnsInvalidResourceSet(
370
+                        $set->getName(),
371
+                        $type->getFullName(),
372
+                        $property->getName()
373
+                    ),
374
+                    500
375
+                );
376
+            }
377
+
378
+            $relatedResourceSetWrapper = $this->_validateResourceSetAndGetWrapper(
379
+                $relatedAssociationSetEnd->getResourceSet()
380
+            );
381
+            if ($relatedResourceSetWrapper === null) {
382
+                $associationSet = null;
383
+            } else {
384
+                $this->_validateResourceType($thisAssociationSetEnd->getResourceType());
385
+                $this->_validateResourceType($relatedAssociationSetEnd->getResourceType());
386
+            }
387
+        }
388
+
389
+        $this->associationSetCache[$cacheKey] = $associationSet;
390
+        return $associationSet;
391
+    }
392
+
393
+    /**
394
+     * Gets the target resource set wrapper for the given navigation property,
395
+     * source resource set wrapper and the source resource type
396
+     *
397
+     * @param ResourceSetWrapper $resourceSetWrapper         Source resource set.
398
+     * @param ResourceType       $resourceType               Source resource type.
399
+     * @param ResourceProperty   $navigationResourceProperty Navigation property.
400
+     *
401
+     * @return ResourceSetWrapper|null Returns instance of ResourceSetWrapper
402
+     *     (describes the entity set and associated configuration) for the
403
+     *     given navigation property. returns NULL if resourceset for the
404
+     *     navigation property is invisible or if metadata provider returns
405
+     *     null resource association set
406
+     */
407
+    public function getResourceSetWrapperForNavigationProperty(
408
+        ResourceSetWrapper $resourceSetWrapper,
409
+        ResourceType $resourceType,
410
+        ResourceProperty $navigationResourceProperty
411
+    ) {
412
+        $associationSet = $this->getResourceAssociationSet(
413
+            $resourceSetWrapper,
414
+            $resourceType,
415
+            $navigationResourceProperty
416
+        );
417
+
418
+        if (!is_null($associationSet)) {
419
+            $relatedAssociationSetEnd = $associationSet->getRelatedResourceAssociationSetEnd(
420
+                $resourceSetWrapper->getResourceSet(),
421
+                $resourceType,
422
+                $navigationResourceProperty
423
+            );
424
+            return $this->_validateResourceSetAndGetWrapper(
425
+                $relatedAssociationSetEnd->getResourceSet()
426
+            );
427
+        }
428
+
429
+        return null;
430
+    }
431
+
432
+    /**
433
+     * Gets the visible resource properties for the given resource type from the given resource set wrapper.
434
+     *
435
+     * @param ResourceSetWrapper $setWrapper Resource set wrapper in question.
436
+     * @param ResourceType       $resourceType       Resource type in question.
437
+     * @return ResourceProperty[] Collection of visible resource properties from the given resource set wrapper and resource type.
438
+     */
439
+    public function getResourceProperties(ResourceSetWrapper $setWrapper, ResourceType $resourceType) {
440
+        if ($resourceType->getResourceTypeKind() != ResourceTypeKind::ENTITY) {
441
+            //Complex resource type
442
+            return $resourceType->getAllProperties();
443
+        }
444
+        //TODO: move this to doctrine annotations
445
+        $cacheKey = $setWrapper->getName() . '_' . $resourceType->getFullName();
446
+        if (!array_key_exists($cacheKey, $this->propertyCache)) {
447
+            //Fill the cache
448
+            $this->propertyCache[$cacheKey] = array();
449
+            foreach ($resourceType->getAllProperties() as $resourceProperty) {
450
+                //Check whether this is a visible navigation property
451
+                //TODO: is this broken?? see #87
452
+                if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY
453
+                    && !is_null($this->getResourceSetWrapperForNavigationProperty($setWrapper, $resourceType, $resourceProperty))
454
+                ) {
455
+                    $this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty;
456
+                } else {
457
+                    //primitive, bag or complex property
458
+                    $this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty;
459
+                }
460
+            }
461
+        }
462
+        return $this->propertyCache[$cacheKey];
463
+
464
+    }
465
+
466
+    /**
467
+     * Wrapper function over _validateResourceSetAndGetWrapper function
468
+     *
469
+     * @param ResourceSet $resourceSet see the comments of _validateResourceSetAndGetWrapper
470
+     *
471
+     * @return ResourceSetWrapper|null see the comments of _validateResourceSetAndGetWrapper
472
+     */
473
+    public function validateResourceSetAndGetWrapper(ResourceSet $resourceSet)
474
+    {
475
+        return $this->_validateResourceSetAndGetWrapper($resourceSet);
476
+    }
477
+
478
+    /**
479
+     * Gets the Edm Schema version compliance to the metadata
480
+     *
481
+     * @return EdmSchemaVersion
482
+     */
483
+    public function getEdmSchemaVersion()
484
+    {
485
+        //The minimal schema version for custom provider is 1.1
486
+        return EdmSchemaVersion::VERSION_1_DOT_1;
487
+    }
488
+
489
+    /**
490
+     * This function perform the following operations
491
+     *  (1) If the cache contain an entry [key, value] for the resourceset then
492
+     *      return the entry-value
493
+     *  (2) If the cache not contain an entry for the resourceset then validate
494
+     *      the resourceset
495
+     *            (a) If valid add entry as [resouceset_name, resourceSetWrapper]
496
+     *            (b) if not valid add entry as [resouceset_name, null]
497
+     *  Note: validating a resourceset means checking the resourceset is visible
498
+     *  or not using configuration
499
+     *
500
+     * @param ResourceSet $resourceSet The resourceset to validate and get the
501
+     *                                 wrapper for
502
+     *
503
+     * @return ResourceSetWrapper|null Returns an instance if a resource set with the given name is visible
504
+     */
505
+    private function _validateResourceSetAndGetWrapper(ResourceSet $resourceSet)
506
+    {
507
+        $cacheKey = $resourceSet->getName();
508
+        if (array_key_exists($cacheKey, $this->setWrapperCache)) {
509
+            return $this->setWrapperCache[$cacheKey];
510
+        }
511
+
512
+        $this->_validateResourceType($resourceSet->getResourceType());
513
+        $wrapper = new ResourceSetWrapper($resourceSet, $this->config);
514
+        if ($wrapper->isVisible()) {
515
+            $this->setWrapperCache[$cacheKey] = $wrapper;
516
+        } else {
517
+            $this->setWrapperCache[$cacheKey] = null;
518
+        }
519
+
520
+        return $this->setWrapperCache[$cacheKey];
521
+    }
522
+
523
+    /**
524
+     * Validates the given instance of ResourceType
525
+     *
526
+     * @param ResourceType $resourceType The ResourceType to validate
527
+     *
528
+     * @return ResourceType
529
+     *
530
+     * @throws ODataException Exception if $resourceType is invalid
531
+     */
532
+    private function _validateResourceType(ResourceType $resourceType)
533
+    {
534
+        $cacheKey = $resourceType->getName();
535
+        if (array_key_exists($cacheKey, $this->typeCache)) {
536
+            return $this->typeCache[$cacheKey];
537
+        }
538
+
539
+        //TODO: Do validation if any for the ResourceType
540
+        $this->typeCache[$cacheKey] = $resourceType;
541
+        return $resourceType;
542
+    }
543
+
544
+    /**
545
+     * Gets the resource type on which the resource property is declared on,
546
+     * If property is not declared in the given resource type, then this
547
+     * function drill down to the inheritance hierarchy of the given resource
548
+     * type to find out the base class in which the property is declared
549
+     *
550
+     * @param ResourceType     $resourceType     The resource type to start looking
551
+     * @param ResourceProperty $resourceProperty The resource property in question
552
+     *
553
+     * @return ResourceType|null Returns reference to the ResourceType on which
554
+     *                                   the $resourceProperty is declared, NULL if
555
+     *                                   $resourceProperty is not declared anywhere
556
+     *                                   in the inheritance hierarchy
557
+     */
558
+    private function _getResourceTypeWherePropertyIsDeclared(ResourceType $resourceType,
559
+        ResourceProperty $resourceProperty
560
+    ) {
561
+        $type = $resourceType;
562
+        while ($type !== null) {
563
+            if ($type->resolvePropertyDeclaredOnThisType($resourceProperty->getName()) !== null) {
564
+                break;
565
+            }
566
+
567
+            $type = $type->getBaseType();
568
+        }
569
+
570
+        return $type;
571
+    }
572
+
573
+    /**
574
+     * Gets the underlying custom expression provider, the end developer is
575
+     * responsible for implementing IExpressionProvider if he choose for
576
+     *
577
+     * @return IExpressionProvider Instance of IExpressionProvider implementation.
578
+     *
579
+     */
580
+    public function getExpressionProvider()
581
+    {
582
+        $expressionProvider = $this->queryProvider->getExpressionProvider();
583
+        if (is_null($expressionProvider)) {
584
+            throw ODataException::createInternalServerError(Messages::providersWrapperExpressionProviderMustNotBeNullOrEmpty());
585
+        }
586
+
587
+        if (!$expressionProvider instanceof IExpressionProvider)
588
+        {
589
+            throw ODataException::createInternalServerError(Messages::providersWrapperInvalidExpressionProviderInstance());
590
+        }
591
+
592
+        return $expressionProvider;
593
+    }
594
+
595
+    /**
596
+     * Indicates if the QueryProvider can handle ordered paging, this means respecting order, skip, and top parameters
597
+     * If the query provider can not handle ordered paging, it must return the entire result set and POData will
598
+     * perform the ordering and paging
599
+     *
600
+     * @return Boolean True if the query provider can handle ordered paging, false if POData should perform the paging
601
+     */
602
+    public function handlesOrderedPaging()
603
+    {
604
+        return $this->queryProvider->handlesOrderedPaging();
605
+    }
606
+
607
+
608
+    /**
609
+     * @param QueryResult $queryResult
610
+     * @param string $methodName
611
+     */
612
+    private function ValidateQueryResult($queryResult, QueryType $queryType, $methodName){
613
+        if (!$queryResult instanceof QueryResult) {
614
+            throw ODataException::createInternalServerError(
615
+                Messages::queryProviderReturnsNonQueryResult($methodName)
616
+            );
617
+        }
618
+
619
+        if($queryType == QueryType::COUNT() || $queryType == QueryType::ENTITIES_WITH_COUNT()){
620
+            //and the provider is supposed to handle the ordered paging they must return a count!
621
+            if($this->queryProvider->handlesOrderedPaging() && !is_numeric($queryResult->count)){
622
+                throw ODataException::createInternalServerError(
623
+                    Messages::queryProviderResultCountMissing($methodName, $queryType)
624
+                );
625
+            }
626
+
627
+            //If POData is supposed to handle the ordered aging they must return results! (possibly empty)
628
+            if(!$this->queryProvider->handlesOrderedPaging() && !is_array($queryResult->results)){
629
+                throw ODataException::createInternalServerError(
630
+                    Messages::queryProviderResultsMissing($methodName, $queryType)
631
+                );
632
+            }
633
+        }
634
+
635
+        if(($queryType == QueryType::ENTITIES() || $queryType == QueryType::ENTITIES_WITH_COUNT()) && !is_array($queryResult->results)){
636
+            throw ODataException::createInternalServerError(
637
+                Messages::queryProviderResultsMissing($methodName, $queryType)
638
+            );
639
+        }
640
+    }
641
+
642
+    /**
643
+     * Gets collection of entities belongs to an entity set
644
+     *
645
+     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
646
+     * @param ResourceSet $resourceSet The entity set containing the entities that need to be fetched
647
+     * @param FilterInfo $filterInfo represents the $filter parameter of the OData query.  NULL if no $filter specified
648
+     * @param InternalOrderByInfo $orderBy The orderBy information
649
+     * @param int $top The top count
650
+     * @param int $skip The skip count
651
+     * @param \POData\UriProcessor\QueryProcessor\SkipTokenParser\SkipTokenInfo $skiptoken
652
+     * @param \POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ExpandedProjectionNode[] $expansion
653
+     *
654
+     * @return QueryResult
655
+     */
656
+    public function getResourceSet(QueryType $queryType, ResourceSet $resourceSet, $filterInfo, $orderBy, $top, $skip, $skiptoken = null, $expansion = null)
657
+    {
658
+
659
+        $queryResult = $this->queryProvider->getResourceSet(
660
+            $queryType,
661
+            $resourceSet,
662
+            $filterInfo,
663
+            $orderBy,
664
+            $top,
665
+            $skip,
666
+            $skiptoken,
667
+            $expansion
668
+        );
669
+
670
+        $this->validateQueryResult($queryResult, $queryType, 'IQueryProvider::getResourceSet');
671
+
672
+        return $queryResult;
673
+    }
674
+
675
+
676
+
677
+    /**
678
+     * Gets an entity instance from an entity set identified by a key
679
+     *
680
+     * @param ResourceSet $resourceSet The entity set containing the entity to fetch
681
+     * @param KeyDescriptor $keyDescriptor The key identifying the entity to fetch
682
+     *
683
+     * @return object|null Returns entity instance if found else null
684
+     */
685
+    public function getResourceFromResourceSet(ResourceSet $resourceSet, KeyDescriptor $keyDescriptor)
686
+    {
687
+        $entityInstance = $this->queryProvider->getResourceFromResourceSet($resourceSet, $keyDescriptor);
688
+        $this->_validateEntityInstance(
689
+            $entityInstance,
690
+            $resourceSet,
691
+            $keyDescriptor,
692
+            'IQueryProvider::getResourceFromResourceSet'
693
+        );
694
+        return $entityInstance;
695
+    }
696
+
697
+    /**
698
+     * Puts an entity instance to entity set identified by a key
699
+     *
700
+     * @param ResourceSet $resourceSet The entity set containing the entity to update
701
+     * @param KeyDescriptor $keyDescriptor The key identifying the entity to update
702
+     *
703
+     * @return bool|null Returns result of executiong query
704
+     */
705
+    public function putResource(
706
+        ResourceSet $resourceSet,
707
+        KeyDescriptor $keyDescriptor,
708
+        $data
709
+    ) {
710
+        $queryResult = $this->queryProvider->putResource(
711
+            $resourceSet,
712
+            $keyDescriptor,
713
+            $data
714
+        );
715
+
716
+        return $queryResult;
717
+    }
718
+
719
+    /**
720
+     * Posts an entity instance to entity set identified by a key
721
+     *
722
+     * @param ResourceSet $resourceSet The entity set containing the entity to update
723
+     *
724
+     * @return bool|null Returns result of executiong query
725
+     */
726
+    public function postResource(
727
+        ResourceSet $resourceSet,
728
+        $data
729
+    ) {
730
+        $queryResult = $this->queryProvider->postResource(
731
+            $resourceSet,
732
+            $data
733
+        );
734
+
735
+        return $queryResult;
736
+    }
737
+
738
+    /**
739
+     * Posts an entity instance to entity set identified by a key
740
+     *
741
+     * @param ResourceSet $resourceSet The entity set containing the entity to update
742
+     * @param KeyDescriptor $keyDescriptor The key identifying the entity to update
743
+     *
744
+     * @return bool|null Returns result of executiong query
745
+     */
746
+    public function deleteResource(
747
+        ResourceSet $resourceSet,
748
+        $keyDescriptor
749
+    ) {
750
+        $queryResult = $this->queryProvider->deleteResource(
751
+            $resourceSet,
752
+            $keyDescriptor
753
+        );
754
+
755
+        return $queryResult;
756
+    }
757
+
758
+    /**
759
+     * Get related resource set for a resource
760
+     *
761
+     * @param QueryType $queryType indicates if this is a query for a count, entities, or entities with a count
762
+     * @param ResourceSet $sourceResourceSet The entity set containing the source entity
763
+     * @param object $sourceEntity The source entity instance.
764
+     * @param ResourceSet      $targetResourceSet    The resource set of containing the target of the navigation property
765
+     * @param ResourceProperty $targetProperty       The navigation property to retrieve
766
+     * @param FilterInfo  $filterInfo represents the $filter parameter of the OData query.  NULL if no $filter specified
767
+     * @param mixed $orderBy sorted order if we want to get the data in some specific order
768
+     * @param int $top number of records which  need to be skip
769
+     * @param String $skip value indicating what records to skip
770
+     *
771
+     * @return QueryResult
772
+     *
773
+     * @throws ODataException
774
+     */
775
+    public function getRelatedResourceSet(
776
+        QueryType $queryType,
777
+        ResourceSet $sourceResourceSet,
778
+        $sourceEntity,
779
+        ResourceSet $targetResourceSet,
780
+        ResourceProperty $targetProperty,
781
+        $filterInfo,
782
+        $orderBy,
783
+        $top,
784
+        $skip
785
+    ) {
786
+
787
+        $queryResult = $this->queryProvider->getRelatedResourceSet(
788
+            $queryType,
789
+            $sourceResourceSet,
790
+            $sourceEntity,
791
+            $targetResourceSet,
792
+            $targetProperty,
793
+            $filterInfo,
794
+            $orderBy,
795
+            $top,
796
+            $skip
797
+        );
798
+
799
+
800
+        $this->validateQueryResult($queryResult, $queryType, 'IQueryProvider::getRelatedResourceSet');
801
+
802
+
803
+        return $queryResult;
804
+    }
805
+
806
+    /**
807
+     * Gets a related entity instance from an entity set identified by a key
808
+     *
809
+     * @param ResourceSet      $sourceResourceSet The entity set related to the entity to be fetched.
810
+     * @param object           $sourceEntity      The related entity instance.
811
+     * @param ResourceSet      $targetResourceSet The entity set from which entity needs to be fetched.
812
+     * @param ResourceProperty $targetProperty    The metadata of the target property.
813
+     * @param KeyDescriptor    $keyDescriptor     The key to identify the entity to be fetched.
814
+     *
815
+     *
816
+     * @return object|null Returns entity instance if found else null
817
+     */
818
+    public function getResourceFromRelatedResourceSet(ResourceSet $sourceResourceSet,
819
+        $sourceEntity, ResourceSet $targetResourceSet, ResourceProperty $targetProperty,
820
+        KeyDescriptor $keyDescriptor
821
+    ) {
822
+        $entityInstance = $this->queryProvider->getResourceFromRelatedResourceSet(
823
+            $sourceResourceSet,
824
+            $sourceEntity,
825
+            $targetResourceSet,
826
+            $targetProperty,
827
+            $keyDescriptor
828
+        );
829
+
830
+        $this->_validateEntityInstance(
831
+            $entityInstance, $targetResourceSet,
832
+            $keyDescriptor,
833
+            'IQueryProvider::getResourceFromRelatedResourceSet'
834
+        );
835
+        return $entityInstance;
836
+    }
837
+
838
+    /**
839
+     * Get related resource for a resource
840
+     *
841
+     * @param ResourceSet      $sourceResourceSet The source resource set
842
+     * @param object           $sourceEntity      The source resource
843
+     * @param ResourceSet      $targetResourceSet The resource set of the navigation
844
+     *                                            property
845
+     * @param ResourceProperty $targetProperty    The navigation property to be
846
+     *                                            retrieved
847
+     *
848
+     * @return object|null The related resource if exists else null
849
+     */
850
+    public function getRelatedResourceReference(ResourceSet $sourceResourceSet,
851
+        $sourceEntity, ResourceSet $targetResourceSet,
852
+        ResourceProperty $targetProperty
853
+    ) {
854
+        $entityInstance = $this->queryProvider->getRelatedResourceReference(
855
+            $sourceResourceSet,
856
+            $sourceEntity,
857
+            $targetResourceSet,
858
+            $targetProperty
859
+        );
860
+
861
+        // we will not throw error if the resource reference is null
862
+        // e.g. Orders(1234)/Customer => Customer can be null, this is
863
+        // allowed if Customer is last segment. consider the following:
864
+        // Orders(1234)/Customer/Orders => here if Customer is null then
865
+        // the UriProcessor will throw error.
866
+        if (!is_null($entityInstance)) {
867
+            $entityName
868
+                = $targetResourceSet
869
+                    ->getResourceType()
870
+                    ->getInstanceType()
871
+                    ->getName();
872
+            if (!is_object($entityInstance)
873
+                || !($entityInstance instanceof $entityName)
874
+            ) {
875
+                throw ODataException::createInternalServerError(
876
+                    Messages::providersWrapperIDSQPMethodReturnsUnExpectedType(
877
+                        $entityName,
878
+                        'IQueryProvider::getRelatedResourceReference'
879
+                    )
880
+                );
881
+            }
882
+
883
+            foreach ($targetProperty->getResourceType()->getKeyProperties()
884
+            as $keyName => $resourceProperty) {
885
+                try {
886
+                    $keyProperty = new \ReflectionProperty(
887
+                        $entityInstance,
888
+                        $keyName
889
+                    );
890
+                    $keyProperty->setAccessible(true);
891
+                    $keyValue = $keyProperty->getValue($entityInstance);
892
+                    if (is_null($keyValue)) {
893
+                        throw ODataException::createInternalServerError(
894
+                            Messages::providersWrapperIDSQPMethodReturnsInstanceWithNullKeyProperties('IDSQP::getRelatedResourceReference')
895
+                        );
896
+                    }
897
+                } catch (\ReflectionException $reflectionException) {
898
+                    //throw ODataException::createInternalServerError(
899
+                    //    Messages::orderByParserFailedToAccessOrInitializeProperty(
900
+                    //        $resourceProperty->getName(), $resourceType->getName()
901
+                    //    )
902
+                    //);
903
+                }
904
+            }
905
+        }
906
+
907
+        return $entityInstance;
908
+    }
909
+
910
+    /**
911
+     * Validate the given entity instance.
912
+     *
913
+     * @param object        $entityInstance Entity instance to validate
914
+     * @param ResourceSet   &$resourceSet   Resource set to which the entity
915
+     *                                      instance belongs to.
916
+     * @param KeyDescriptor &$keyDescriptor The key descriptor.
917
+     * @param string        $methodName     Method from which this function
918
+     *                                      invoked.
919
+     *
920
+     * @return void
921
+     *
922
+     * @throws ODataException
923
+     */
924
+    private function _validateEntityInstance($entityInstance,
925
+        ResourceSet &$resourceSet,
926
+        KeyDescriptor &$keyDescriptor,
927
+        $methodName
928
+    ) {
929
+        if (is_null($entityInstance)) {
930
+            throw ODataException::createResourceNotFoundError($resourceSet->getName());
931
+        }
932
+
933
+        $entityName = $resourceSet->getResourceType()->getInstanceType()->getName();
934
+        if (!is_object($entityInstance)
935
+            || !($entityInstance instanceof $entityName)
936
+        ) {
937
+            throw ODataException::createInternalServerError(
938
+                Messages::providersWrapperIDSQPMethodReturnsUnExpectedType(
939
+                    $entityName,
940
+                    $methodName
941
+                )
942
+            );
943
+        }
944
+
945
+        foreach ($keyDescriptor->getValidatedNamedValues()
946
+            as $keyName => $valueDescription) {
947
+            try {
948
+                $keyProperty = new \ReflectionProperty($entityInstance, $keyName);
949
+                $keyProperty->setAccessible(true);
950
+                $keyValue = $keyProperty->getValue($entityInstance);
951
+                if (is_null($keyValue)) {
952
+                    throw ODataException::createInternalServerError(
953
+                        Messages::providersWrapperIDSQPMethodReturnsInstanceWithNullKeyProperties($methodName)
954
+                    );
955
+                }
956
+
957
+                $convertedValue
958
+                    = $valueDescription[1]->convert($valueDescription[0]);
959
+                if ($keyValue != $convertedValue) {
960
+                    throw ODataException::createInternalServerError(
961
+                        Messages::providersWrapperIDSQPMethodReturnsInstanceWithNonMatchingKeys($methodName)
962
+                    );
963
+                }
964
+            } catch (\ReflectionException $reflectionException) {
965
+                //throw ODataException::createInternalServerError(
966
+                //  Messages::orderByParserFailedToAccessOrInitializeProperty(
967
+                //      $resourceProperty->getName(), $resourceType->getName()
968
+                //  )
969
+                //);
970
+            }
971
+        }
972
+    }
973
+
974
+    /**
975
+     * Assert that the given condition is true.
976
+     *
977
+     * @param boolean $condition         Condition to be asserted.
978
+     * @param string  $conditionAsString String containing message incase
979
+     *                                   if assertion fails.
980
+     *
981
+     * @throws InvalidOperationException Incase if assertion fails.
982
+     *
983
+     * @return void
984
+     */
985
+    protected function assert($condition, $conditionAsString)
986
+    {
987
+        if (!$condition) {
988
+            throw new InvalidOperationException("Unexpected state, expecting $conditionAsString");
989
+        }
990
+    }
991 991
 }
992 992
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -609,30 +609,30 @@
 block discarded – undo
609 609
 	 * @param QueryResult $queryResult
610 610
 	 * @param string $methodName
611 611
 	 */
612
-	private function ValidateQueryResult($queryResult, QueryType $queryType, $methodName){
612
+	private function ValidateQueryResult($queryResult, QueryType $queryType, $methodName) {
613 613
 		if (!$queryResult instanceof QueryResult) {
614 614
 			throw ODataException::createInternalServerError(
615 615
 				Messages::queryProviderReturnsNonQueryResult($methodName)
616 616
 			);
617 617
 		}
618 618
 
619
-		if($queryType == QueryType::COUNT() || $queryType == QueryType::ENTITIES_WITH_COUNT()){
619
+		if ($queryType == QueryType::COUNT() || $queryType == QueryType::ENTITIES_WITH_COUNT()) {
620 620
 			//and the provider is supposed to handle the ordered paging they must return a count!
621
-			if($this->queryProvider->handlesOrderedPaging() && !is_numeric($queryResult->count)){
621
+			if ($this->queryProvider->handlesOrderedPaging() && !is_numeric($queryResult->count)) {
622 622
 				throw ODataException::createInternalServerError(
623 623
 					Messages::queryProviderResultCountMissing($methodName, $queryType)
624 624
 				);
625 625
 			}
626 626
 
627 627
 			//If POData is supposed to handle the ordered aging they must return results! (possibly empty)
628
-			if(!$this->queryProvider->handlesOrderedPaging() && !is_array($queryResult->results)){
628
+			if (!$this->queryProvider->handlesOrderedPaging() && !is_array($queryResult->results)) {
629 629
 				throw ODataException::createInternalServerError(
630 630
 					Messages::queryProviderResultsMissing($methodName, $queryType)
631 631
 				);
632 632
 			}
633 633
 		}
634 634
 
635
-		if(($queryType == QueryType::ENTITIES() || $queryType == QueryType::ENTITIES_WITH_COUNT()) && !is_array($queryResult->results)){
635
+		if (($queryType == QueryType::ENTITIES() || $queryType == QueryType::ENTITIES_WITH_COUNT()) && !is_array($queryResult->results)) {
636 636
 			throw ODataException::createInternalServerError(
637 637
 				Messages::queryProviderResultsMissing($methodName, $queryType)
638 638
 			);
Please login to merge, or discard this patch.
src/POData/Providers/Query/QueryResult.php 2 patches
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -23,18 +23,18 @@
 block discarded – undo
23 23
      *
24 24
      * @throws \InvalidArgumentException if $count is not numeric
25 25
      */
26
-    public static function adjustCountForPaging($count, $top, $skip){
26
+    public static function adjustCountForPaging($count, $top, $skip) {
27 27
 
28
-        if(!is_numeric($count)) throw new \InvalidArgumentException('$count');
28
+        if (!is_numeric($count)) throw new \InvalidArgumentException('$count');
29 29
 
30 30
         //treat nulls like 0
31
-        if(is_null($skip)) $skip = 0;
31
+        if (is_null($skip)) $skip = 0;
32 32
 
33 33
 
34 34
         $count = $count - $skip; //eliminate the skipped records
35
-        if($count < 0) return 0; //if there aren't enough to skip, the count is 0
35
+        if ($count < 0) return 0; //if there aren't enough to skip, the count is 0
36 36
 
37
-        if(is_null($top)) return $count; //if there's no top, then it's the count as is
37
+        if (is_null($top)) return $count; //if there's no top, then it's the count as is
38 38
 
39 39
         return min($count, $top); //count is top, unless there aren't enough records
40 40
 
Please login to merge, or discard this patch.
Braces   +15 added lines, -5 removed lines patch added patch discarded remove patch
@@ -25,16 +25,26 @@
 block discarded – undo
25 25
      */
26 26
     public static function adjustCountForPaging($count, $top, $skip){
27 27
 
28
-        if(!is_numeric($count)) throw new \InvalidArgumentException('$count');
28
+        if(!is_numeric($count)) {
29
+            throw new \InvalidArgumentException('$count');
30
+        }
29 31
 
30 32
         //treat nulls like 0
31
-        if(is_null($skip)) $skip = 0;
33
+        if(is_null($skip)) {
34
+            $skip = 0;
35
+        }
32 36
 
33 37
 
34 38
         $count = $count - $skip; //eliminate the skipped records
35
-        if($count < 0) return 0; //if there aren't enough to skip, the count is 0
36
-
37
-        if(is_null($top)) return $count; //if there's no top, then it's the count as is
39
+        if($count < 0) {
40
+            return 0;
41
+        }
42
+        //if there aren't enough to skip, the count is 0
43
+
44
+        if(is_null($top)) {
45
+            return $count;
46
+        }
47
+        //if there's no top, then it's the count as is
38 48
 
39 49
         return min($count, $top); //count is top, unless there aren't enough records
40 50
 
Please login to merge, or discard this patch.
src/POData/Providers/Metadata/Type/Binary.php 1 patch
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -125,7 +125,7 @@
 block discarded – undo
125 125
             return false;    
126 126
         }
127 127
 
128
-        if (!ctype_xdigit($value)){
128
+        if (!ctype_xdigit($value)) {
129 129
             $outValue = null;
130 130
             return false;
131 131
         }
Please login to merge, or discard this patch.