| Total Complexity | 110 | 
| Total Lines | 953 | 
| Duplicated Lines | 0 % | 
| Changes | 4 | ||
| Bugs | 2 | Features | 0 | 
Complex classes like ObjectModelSerializer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ObjectModelSerializer, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 33 | class ObjectModelSerializer extends ObjectModelSerializerBase  | 
            ||
| 34 | { | 
            ||
| 35 | /**  | 
            ||
| 36 | * Creates new instance of ObjectModelSerializer.  | 
            ||
| 37 | *  | 
            ||
| 38 | * @param IService $service  | 
            ||
| 39 | *  | 
            ||
| 40 | * @param RequestDescription $request the request submitted by the client.  | 
            ||
| 41 | *  | 
            ||
| 42 | */  | 
            ||
| 43 | public function __construct(IService $service, RequestDescription $request)  | 
            ||
| 44 |     { | 
            ||
| 45 | parent::__construct($service, $request);  | 
            ||
| 46 | }  | 
            ||
| 47 | |||
| 48 | /**  | 
            ||
| 49 | * Write a top level entry resource.  | 
            ||
| 50 | *  | 
            ||
| 51 | * @param mixed $entryObject Reference to the entry object to be written.  | 
            ||
| 52 | *  | 
            ||
| 53 | * @return ODataEntry  | 
            ||
| 54 | */  | 
            ||
| 55 | public function writeTopLevelElement($entryObject)  | 
            ||
| 56 |     { | 
            ||
| 57 | $requestTargetSource = $this->request->getTargetSource();  | 
            ||
| 58 | |||
| 59 | $resourceType = null;  | 
            ||
| 60 |         if ($requestTargetSource == TargetSource::ENTITY_SET) { | 
            ||
| 61 | $resourceType = $this->request->getTargetResourceType();  | 
            ||
| 62 |         } else { | 
            ||
| 63 | $this->assert(  | 
            ||
| 64 | $requestTargetSource == TargetSource::PROPERTY,  | 
            ||
| 65 | '$requestTargetSource == TargetSource::PROPERTY'  | 
            ||
| 66 | );  | 
            ||
| 67 | $resourceProperty = $this->request->getProjectedProperty();  | 
            ||
| 68 | //$this->assert($resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE, '$resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE');  | 
            ||
| 69 | $resourceType = $resourceProperty->getResourceType();  | 
            ||
| 70 | }  | 
            ||
| 71 | |||
| 72 | $needPop = $this->pushSegmentForRoot();  | 
            ||
| 73 | $entry = $this->_writeEntryElement(  | 
            ||
| 74 | $entryObject,  | 
            ||
| 75 | $resourceType,  | 
            ||
| 76 | $this->request->getRequestUrl()->getUrlAsString(),  | 
            ||
| 77 | $this->request->getContainerName()  | 
            ||
| 78 | );  | 
            ||
| 79 | |||
| 80 | $toplevel_properties = $this->_writeCustomTopLevelProperties();  | 
            ||
| 81 | array_push($entry->customProperties->properties, ...$toplevel_properties);  | 
            ||
| 82 | |||
| 83 | $this->popSegment($needPop);  | 
            ||
| 84 | return $entry;  | 
            ||
| 85 | }  | 
            ||
| 86 | |||
| 87 | /**  | 
            ||
| 88 | * Write top level feed element.  | 
            ||
| 89 | *  | 
            ||
| 90 | * @param array &$entryObjects Array of entry resources to be written.  | 
            ||
| 91 | *  | 
            ||
| 92 | * @return ODataFeed.  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 93 | */  | 
            ||
| 94 | public function writeTopLevelElements(&$entryObjects)  | 
            ||
| 95 |     { | 
            ||
| 96 | $this->assert(is_iterable($entryObjects), 'is_iterable($entryObjects)');  | 
            ||
| 97 | $requestTargetSource = $this->request->getTargetSource();  | 
            ||
| 98 | $title = null;  | 
            ||
| 99 |         if ($requestTargetSource == TargetSource::ENTITY_SET) { | 
            ||
| 100 | $title = $this->request->getContainerName();  | 
            ||
| 101 |         } else { | 
            ||
| 102 | $this->assert(  | 
            ||
| 103 | $requestTargetSource == TargetSource::PROPERTY,  | 
            ||
| 104 | '$requestTargetSource == TargetSource::PROPERTY'  | 
            ||
| 105 | );  | 
            ||
| 106 | $resourceProperty = $this->request->getProjectedProperty();  | 
            ||
| 107 | $this->assert(  | 
            ||
| 108 | $resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE,  | 
            ||
| 109 | '$resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE'  | 
            ||
| 110 | );  | 
            ||
| 111 | $title = $resourceProperty->getName();  | 
            ||
| 112 | }  | 
            ||
| 113 | |||
| 114 | $relativeUri = $this->request->getIdentifier();  | 
            ||
| 115 | $feed = new ODataFeed();  | 
            ||
| 116 | |||
| 117 |         if ($this->request->queryType == QueryType::ENTITIES_WITH_COUNT) { | 
            ||
| 118 | $feed->rowCount = $this->request->getCountValue();  | 
            ||
| 119 | }  | 
            ||
| 120 | |||
| 121 | $toplevel_properties = $this->_writeCustomTopLevelProperties();  | 
            ||
| 122 | array_push($feed->customProperties->properties, ...$toplevel_properties);  | 
            ||
| 123 | |||
| 124 | $needPop = $this->pushSegmentForRoot();  | 
            ||
| 125 | $targetResourceType = $this->request->getTargetResourceType();  | 
            ||
| 126 | $this->_writeFeedElements(  | 
            ||
| 127 | $entryObjects,  | 
            ||
| 128 | $targetResourceType,  | 
            ||
| 129 | $title,  | 
            ||
| 130 | $this->request->getRequestUrl()->getUrlAsString(),  | 
            ||
| 131 | $relativeUri,  | 
            ||
| 132 | $feed  | 
            ||
| 133 | );  | 
            ||
| 134 | $this->popSegment($needPop);  | 
            ||
| 135 | return $feed;  | 
            ||
| 136 | }  | 
            ||
| 137 | |||
| 138 | /**  | 
            ||
| 139 | * Write top level url element.  | 
            ||
| 140 | *  | 
            ||
| 141 | * @param mixed $entryObject The entry resource whose url to be written.  | 
            ||
| 142 | *  | 
            ||
| 143 | * @return ODataURL  | 
            ||
| 144 | */  | 
            ||
| 145 | public function writeUrlElement($entryObject)  | 
            ||
| 146 |     { | 
            ||
| 147 | $url = new ODataURL();  | 
            ||
| 148 |         if (!is_null($entryObject)) { | 
            ||
| 149 | $currentResourceType = $this->getCurrentResourceSetWrapper()->getResourceType();  | 
            ||
| 150 | $relativeUri = $this->getEntryInstanceKey(  | 
            ||
| 151 | $entryObject,  | 
            ||
| 152 | $currentResourceType,  | 
            ||
| 153 | $this->getCurrentResourceSetWrapper()->getName()  | 
            ||
| 154 | );  | 
            ||
| 155 | |||
| 156 | $url->url = rtrim($this->absoluteServiceUri, '/') . '/' . $relativeUri;  | 
            ||
| 157 | }  | 
            ||
| 158 | |||
| 159 | return $url;  | 
            ||
| 160 | }  | 
            ||
| 161 | |||
| 162 | /**  | 
            ||
| 163 | * Write top level url collection.  | 
            ||
| 164 | *  | 
            ||
| 165 | * @param array $entryObjects Array of entry resources  | 
            ||
| 166 | * whose url to be written.  | 
            ||
| 167 | *  | 
            ||
| 168 | * @return ODataURLCollection  | 
            ||
| 169 | */  | 
            ||
| 170 | public function writeUrlElements($entryObjects)  | 
            ||
| 190 | }  | 
            ||
| 191 | |||
| 192 | /**  | 
            ||
| 193 | * Write top level complex resource.  | 
            ||
| 194 | *  | 
            ||
| 195 | * @param mixed &$complexValue The complex object to be  | 
            ||
| 196 | * written.  | 
            ||
| 197 | * @param string $propertyName The name of the  | 
            ||
| 198 | * complex property.  | 
            ||
| 199 | * @param ResourceType &$resourceType Describes the type of  | 
            ||
| 200 | * complex object.  | 
            ||
| 201 | *  | 
            ||
| 202 | * @return ODataPropertyContent  | 
            ||
| 203 | */  | 
            ||
| 204 | public function writeTopLevelComplexObject(  | 
            ||
| 205 | &$complexValue,  | 
            ||
| 206 | $propertyName,  | 
            ||
| 207 | ResourceType &$resourceType  | 
            ||
| 208 |     ) { | 
            ||
| 209 | $propertyContent = new ODataPropertyContent();  | 
            ||
| 210 | $this->_writeComplexValue(  | 
            ||
| 211 | $complexValue,  | 
            ||
| 212 | $propertyName, $resourceType, null,  | 
            ||
| 213 | $propertyContent  | 
            ||
| 214 | );  | 
            ||
| 215 | |||
| 216 | return $propertyContent;  | 
            ||
| 217 | }  | 
            ||
| 218 | |||
| 219 | /**  | 
            ||
| 220 | * Write top level bag resource.  | 
            ||
| 221 | *  | 
            ||
| 222 | * @param mixed &$BagValue The bag object to be  | 
            ||
| 223 | * written.  | 
            ||
| 224 | * @param string $propertyName The name of the  | 
            ||
| 225 | * bag property.  | 
            ||
| 226 | * @param ResourceType &$resourceType Describes the type of  | 
            ||
| 227 | * bag object.  | 
            ||
| 228 | *  | 
            ||
| 229 | * @return ODataPropertyContent  | 
            ||
| 230 | */  | 
            ||
| 231 | public function writeTopLevelBagObject(  | 
            ||
| 232 | &$BagValue,  | 
            ||
| 233 | $propertyName,  | 
            ||
| 234 | ResourceType &$resourceType  | 
            ||
| 235 |     ) { | 
            ||
| 236 | |||
| 237 | $propertyContent = new ODataPropertyContent();  | 
            ||
| 238 | $this->_writeBagValue(  | 
            ||
| 239 | $BagValue,  | 
            ||
| 240 | $propertyName, $resourceType, null,  | 
            ||
| 241 | $propertyContent  | 
            ||
| 242 | );  | 
            ||
| 243 | |||
| 244 | return $propertyContent;  | 
            ||
| 245 | }  | 
            ||
| 246 | |||
| 247 | /**  | 
            ||
| 248 | * Write top level primitive value.  | 
            ||
| 249 | *  | 
            ||
| 250 | * @param mixed &$primitiveValue The primitve value to be  | 
            ||
| 251 | * written.  | 
            ||
| 252 | * @param ResourceProperty &$resourceProperty Resource property  | 
            ||
| 253 | * describing the  | 
            ||
| 254 | * primitive property  | 
            ||
| 255 | * to be written.  | 
            ||
| 256 | *  | 
            ||
| 257 | * @return ODataPropertyContent  | 
            ||
| 258 | */  | 
            ||
| 259 | public function writeTopLevelPrimitive(  | 
            ||
| 260 | &$primitiveValue,  | 
            ||
| 261 | ResourceProperty &$resourceProperty  | 
            ||
| 262 |     ) { | 
            ||
| 263 | $propertyContent = new ODataPropertyContent();  | 
            ||
| 264 | $propertyContent->properties[] = new ODataProperty();  | 
            ||
| 265 | $this->_writePrimitiveValue(  | 
            ||
| 266 | $primitiveValue,  | 
            ||
| 267 | $resourceProperty,  | 
            ||
| 268 | $propertyContent->properties[0]  | 
            ||
| 269 | );  | 
            ||
| 270 | |||
| 271 | return $propertyContent;  | 
            ||
| 272 | }  | 
            ||
| 273 | |||
| 274 | /**  | 
            ||
| 275 | * Write an entry element.  | 
            ||
| 276 | *  | 
            ||
| 277 | * @param mixed $entryObject Object representing entry element.  | 
            ||
| 278 | * @param ResourceType $resourceType Expected type of the entry object.  | 
            ||
| 279 | * @param string $absoluteUri Absolute uri of the entry element.  | 
            ||
| 280 | * @param string $relativeUri Relative uri of the entry element.  | 
            ||
| 281 | *  | 
            ||
| 282 | * @return ODataEntry  | 
            ||
| 283 | */  | 
            ||
| 284 | private function _writeEntryElement(  | 
            ||
| 285 | $entryObject,  | 
            ||
| 286 | ResourceType $resourceType,  | 
            ||
| 287 | $absoluteUri,  | 
            ||
| 288 | $relativeUri  | 
            ||
| 289 |     ) { | 
            ||
| 290 | $entry = new ODataEntry();  | 
            ||
| 291 | $entry->resourceSetName = $this->getCurrentResourceSetWrapper()->getName();  | 
            ||
| 292 | |||
| 293 |         if (is_null($entryObject)) { | 
            ||
| 294 | //According to atom standard an empty entry must have an Author  | 
            ||
| 295 | //node.  | 
            ||
| 296 |         } else { | 
            ||
| 297 | $actualResourceType = $this->service->getProvidersWrapper()->resolveResourceTypeByClassname(get_class($entryObject));  | 
            ||
| 298 |             if ($actualResourceType) { | 
            ||
| 299 | $actualResourceSet = $actualResourceType->getCustomState();  | 
            ||
| 300 |             } else { | 
            ||
| 301 | $actualResourceType = $resourceType;  | 
            ||
| 302 | $actualResourceSet = $this->getCurrentResourceSetWrapper();  | 
            ||
| 303 | }  | 
            ||
| 304 | $relativeUri = $this->getEntryInstanceKey(  | 
            ||
| 305 | $entryObject,  | 
            ||
| 306 | $actualResourceType,  | 
            ||
| 307 | $actualResourceSet->getName()  | 
            ||
| 308 | );  | 
            ||
| 309 | $entry->resourceSetName = $actualResourceSet->getName();  | 
            ||
| 310 | |||
| 311 | $absoluteUri = rtrim($this->absoluteServiceUri, '/') . '/' . $relativeUri;  | 
            ||
| 312 | $title = $resourceType->getName();  | 
            ||
| 313 | $this->_writeMediaResourceMetadata(  | 
            ||
| 314 | $entryObject,  | 
            ||
| 315 | $actualResourceType,  | 
            ||
| 316 | $title,  | 
            ||
| 317 | $relativeUri,  | 
            ||
| 318 | $entry  | 
            ||
| 319 | );  | 
            ||
| 320 | |||
| 321 | $entry->id = $absoluteUri;  | 
            ||
| 322 | $entry->eTag = $this->getETagForEntry($entryObject, $resourceType);  | 
            ||
| 323 | $entry->title = $title;  | 
            ||
| 324 | $entry->editLink = $relativeUri;  | 
            ||
| 325 | $entry->type = $actualResourceType->getFullName();  | 
            ||
| 326 | |||
| 327 | // Do not calculate the custom properties if the metadata level is none  | 
            ||
| 328 | $responseContentType = $this->service->getResponseContentType($this->request, $this->request->getUriProcessor(), $this->service);  | 
            ||
| 329 | $matches = [];  | 
            ||
| 330 |             preg_match('/[^;]+(?<accept_ext>;[^;]+)*/', $responseContentType, $matches); | 
            ||
| 331 | $accept_ext = isset($matches['accept_ext']) ? $matches['accept_ext'] : '';  | 
            ||
| 332 |             $accept_extensions_tmp = explode(';', trim($accept_ext, ' \n\r\t\v\0;')); | 
            ||
| 333 | $accept_extensions = [];  | 
            ||
| 334 |             foreach($accept_extensions_tmp as $accept_extension) { | 
            ||
| 335 |                 $parts = explode('=', $accept_extension); | 
            ||
| 336 | $accept_extensions[$parts[0]] = $accept_extension;  | 
            ||
| 337 | }  | 
            ||
| 338 | |||
| 339 |             if (!isset($accept_extensions['odata']) || $accept_extensions['odata'] != JsonLightMetadataLevel::NONE) { | 
            ||
| 340 | $this->_writeCustomProperties(  | 
            ||
| 341 | $entryObject,  | 
            ||
| 342 | $entry->customProperties  | 
            ||
| 343 | );  | 
            ||
| 344 | }  | 
            ||
| 345 | |||
| 346 | $odataPropertyContent = new ODataPropertyContent();  | 
            ||
| 347 | $this->_writeObjectProperties(  | 
            ||
| 348 | $entryObject,  | 
            ||
| 349 | $actualResourceType,  | 
            ||
| 350 | $absoluteUri,  | 
            ||
| 351 | $relativeUri,  | 
            ||
| 352 | $entry,  | 
            ||
| 353 | $odataPropertyContent  | 
            ||
| 354 | );  | 
            ||
| 355 | $entry->propertyContent = $odataPropertyContent;  | 
            ||
| 356 | }  | 
            ||
| 357 | |||
| 358 | return $entry;  | 
            ||
| 359 | }  | 
            ||
| 360 | |||
| 361 | /**  | 
            ||
| 362 | * Writes the feed elements  | 
            ||
| 363 | *  | 
            ||
| 364 | * @param array &$entryObjects Array of entries in the feed element.  | 
            ||
| 365 | * @param ResourceType &$resourceType The resource type of the f the elements  | 
            ||
| 366 | * in the collection.  | 
            ||
| 367 | * @param string $title Title of the feed element.  | 
            ||
| 368 | * @param string $absoluteUri Absolute uri representing the feed element.  | 
            ||
| 369 | * @param string $relativeUri Relative uri representing the feed element.  | 
            ||
| 370 | * @param ODataFeed &$feed Feed to write to.  | 
            ||
| 371 | *  | 
            ||
| 372 | * @return void  | 
            ||
| 373 | */  | 
            ||
| 374 | private function _writeFeedElements(  | 
            ||
| 375 | &$entryObjects,  | 
            ||
| 376 | ResourceType &$resourceType,  | 
            ||
| 377 | $title,  | 
            ||
| 378 | $absoluteUri,  | 
            ||
| 379 | $relativeUri,  | 
            ||
| 380 | ODataFeed &$feed  | 
            ||
| 381 |     ) { | 
            ||
| 382 | $this->assert(is_iterable($entryObjects) || $entryObjects instanceof ArrayAccess, '_writeFeedElements::is_iterable($entryObjects)');  | 
            ||
| 383 | $feed->id = $absoluteUri;  | 
            ||
| 384 | $feed->title = $title;  | 
            ||
| 385 | $feed->selfLink = new ODataLink();  | 
            ||
| 386 | $feed->selfLink->name = ODataConstants::ATOM_SELF_RELATION_ATTRIBUTE_VALUE;  | 
            ||
| 387 | $feed->selfLink->title = $title;  | 
            ||
| 388 | $feed->selfLink->url = $relativeUri;  | 
            ||
| 389 | |||
| 390 |         if (empty($entryObjects)) { | 
            ||
| 391 | //TODO // ATOM specification: if a feed contains no entries,  | 
            ||
| 392 | //then the feed should have at least one Author tag  | 
            ||
| 393 |         } else { | 
            ||
| 394 |             foreach ($entryObjects as $entryObject) { | 
            ||
| 395 | $feed->entries[] = $this->_writeEntryElement($entryObject, $resourceType, null, null);  | 
            ||
| 396 | }  | 
            ||
| 397 | |||
| 398 |             if ($this->needNextPageLink(count($entryObjects))) { | 
            ||
| 399 | $end = is_array($entryObjects) ? end($entryObjects) : (method_exists($entryObjects, 'last') ? $entryObjects->last() : null);  | 
            ||
| 400 | $feed->nextPageLink = $this->getNextLinkUri($end, $absoluteUri);  | 
            ||
| 401 | }  | 
            ||
| 402 | }  | 
            ||
| 403 | }  | 
            ||
| 404 | |||
| 405 | private function _writeCustomProperties(  | 
            ||
| 406 | $customObject,  | 
            ||
| 407 | ODataPropertyContent &$odataPropertyContent  | 
            ||
| 408 | )  | 
            ||
| 409 |     { | 
            ||
| 410 | $properties = $this->service->getQueryProvider()->getCustomProperties($customObject);  | 
            ||
| 411 | |||
| 412 | //First write out primitve types  | 
            ||
| 413 |         foreach ($properties as $name => $value) { | 
            ||
| 414 | $odataProperty = new ODataProperty();  | 
            ||
| 415 | $odataProperty->name = $name;  | 
            ||
| 416 | $odataProperty->value = $value;  | 
            ||
| 417 | $odataPropertyContent->properties[] = $odataProperty;  | 
            ||
| 418 | }  | 
            ||
| 419 | }  | 
            ||
| 420 | |||
| 421 | private function _writeCustomTopLevelProperties()  | 
            ||
| 422 |     { | 
            ||
| 423 | $odataProperties = [];  | 
            ||
| 424 | $properties = $this->service->getQueryProvider()->getCustomFeedProperties();  | 
            ||
| 425 | |||
| 426 | //First write out primitve types  | 
            ||
| 427 |         foreach ($properties as $name => $value) { | 
            ||
| 428 | $odataProperty = new ODataProperty();  | 
            ||
| 429 | $odataProperty->name = $name;  | 
            ||
| 430 | $odataProperty->value = $value;  | 
            ||
| 431 | $odataProperties[] = $odataProperty;  | 
            ||
| 432 | }  | 
            ||
| 433 | return $odataProperties;  | 
            ||
| 434 | }  | 
            ||
| 435 | |||
| 436 | /**  | 
            ||
| 437 | * Write values of properties of given entry (resource) or complex object.  | 
            ||
| 438 | *  | 
            ||
| 439 | * @param mixed $customObject Entity or complex object  | 
            ||
| 440 | * with properties  | 
            ||
| 441 | * to write out.  | 
            ||
| 442 | * @param ResourceType &$resourceType Resource type describing  | 
            ||
| 443 | * the metadata of  | 
            ||
| 444 | * the custom object.  | 
            ||
| 445 | * @param string $absoluteUri Absolute uri for the given  | 
            ||
| 446 | * entry object  | 
            ||
| 447 | * NULL for complex object.  | 
            ||
| 448 | * @param string $relativeUri Relative uri for the given  | 
            ||
| 449 | * custom object.  | 
            ||
| 450 | * @param ODataEntry ODataEntry|null ODataEntry instance to  | 
            ||
| 451 | * place links and  | 
            ||
| 452 | * expansion of the  | 
            ||
| 453 | * entry object,  | 
            ||
| 454 | * NULL for complex object.  | 
            ||
| 455 | * @param ODataPropertyContent &$odataPropertyContent ODataPropertyContent  | 
            ||
| 456 | * instance in which  | 
            ||
| 457 | * to place the values.  | 
            ||
| 458 | *  | 
            ||
| 459 | * @return void  | 
            ||
| 460 | */  | 
            ||
| 461 | private function _writeObjectProperties(  | 
            ||
| 462 | $customObject,  | 
            ||
| 463 | ResourceType &$resourceType,  | 
            ||
| 464 | $absoluteUri,  | 
            ||
| 465 | $relativeUri,  | 
            ||
| 466 | &$odataEntry,  | 
            ||
| 467 | ODataPropertyContent &$odataPropertyContent  | 
            ||
| 468 |     ) { | 
            ||
| 469 | $resourceTypeKind = $resourceType->getResourceTypeKind();  | 
            ||
| 470 | if (is_null($absoluteUri) == ($resourceTypeKind == ResourceTypeKind::ENTITY)  | 
            ||
| 471 |         ) { | 
            ||
| 472 | throw ODataException::createInternalServerError(  | 
            ||
| 473 | Messages::badProviderInconsistentEntityOrComplexTypeUsage(  | 
            ||
| 474 | $resourceType->getName()  | 
            ||
| 475 | )  | 
            ||
| 476 | );  | 
            ||
| 477 | }  | 
            ||
| 478 | |||
| 479 | $this->assert(  | 
            ||
| 480 | (($resourceTypeKind == ResourceTypeKind::ENTITY) && ($odataEntry instanceof ODataEntry))  | 
            ||
| 481 | || (($resourceTypeKind == ResourceTypeKind::COMPLEX) && is_null($odataEntry)),  | 
            ||
| 482 | '(($resourceTypeKind == ResourceTypeKind::ENTITY) && ($odataEntry instanceof ODataEntry))  | 
            ||
| 483 | || (($resourceTypeKind == ResourceTypeKind::COMPLEX) && is_null($odataEntry))'  | 
            ||
| 484 | );  | 
            ||
| 485 | $projectionNodes = null;  | 
            ||
| 486 | $navigationProperties = null;  | 
            ||
| 487 |         if ($resourceTypeKind == ResourceTypeKind::ENTITY) { | 
            ||
| 488 | $projectionNodes = $this->getProjectionNodes();  | 
            ||
| 489 | $navigationProperties = array();  | 
            ||
| 490 | }  | 
            ||
| 491 | |||
| 492 |         if (is_null($projectionNodes)) { | 
            ||
| 493 | //This is the code path to handle properties of Complex type  | 
            ||
| 494 | //or Entry without projection (i.e. no expansion or selection)  | 
            ||
| 495 | $resourceProperties = array();  | 
            ||
| 496 |             if ($resourceTypeKind == ResourceTypeKind::ENTITY) { | 
            ||
| 497 | // If custom object is an entry then it can contain navigation  | 
            ||
| 498 | // properties which are invisible (because the corresponding  | 
            ||
| 499 | // resource set is invisible).  | 
            ||
| 500 | // IDSMP::getResourceProperties will give collection of properties  | 
            ||
| 501 | // which are visible.  | 
            ||
| 502 | $currentResourceSetWrapper1 = $this->getCurrentResourceSetWrapper();  | 
            ||
| 503 | $resourceProperties = $this->service  | 
            ||
| 504 | ->getProvidersWrapper()  | 
            ||
| 505 | ->getResourceProperties(  | 
            ||
| 506 | $currentResourceSetWrapper1,  | 
            ||
| 507 | $resourceType  | 
            ||
| 508 | );  | 
            ||
| 509 |             } else { | 
            ||
| 510 | $resourceProperties = $resourceType->getAllProperties();  | 
            ||
| 511 | }  | 
            ||
| 512 | |||
| 513 | //First write out primitve types  | 
            ||
| 514 |             foreach ($resourceProperties as $name => $resourceProperty) { | 
            ||
| 515 | if ($resourceProperty->getKind() == ResourcePropertyKind::PRIMITIVE  | 
            ||
| 516 | || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY)  | 
            ||
| 517 | || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::ETAG)  | 
            ||
| 518 | || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY | ResourcePropertyKind::ETAG)  | 
            ||
| 519 |                 ) { | 
            ||
| 520 | $odataProperty = new ODataProperty();  | 
            ||
| 521 | $primitiveValue = $this->getPropertyValue($customObject, $resourceType, $resourceProperty);  | 
            ||
| 522 | $this->_writePrimitiveValue($primitiveValue, $resourceProperty, $odataProperty);  | 
            ||
| 523 | $odataPropertyContent->properties[] = $odataProperty;  | 
            ||
| 524 | }  | 
            ||
| 525 | }  | 
            ||
| 526 | |||
| 527 | //Write out bag and complex type  | 
            ||
| 528 | $i = 0;  | 
            ||
| 529 |             foreach ($resourceProperties as $resourceProperty) { | 
            ||
| 530 |                 if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG)) { | 
            ||
| 531 | //Handle Bag Property (Bag of Primitive or complex)  | 
            ||
| 532 | $propertyValue = $this->getPropertyValue($customObject, $resourceType, $resourceProperty);  | 
            ||
| 533 | $resourceType2 = $resourceProperty->getResourceType();  | 
            ||
| 534 | $this->_writeBagValue(  | 
            ||
| 535 | $propertyValue,  | 
            ||
| 536 | $resourceProperty->getName(),  | 
            ||
| 537 | $resourceType2,  | 
            ||
| 538 | $relativeUri . '/' . $resourceProperty->getName(),  | 
            ||
| 539 | $odataPropertyContent  | 
            ||
| 540 | );  | 
            ||
| 541 |                 } else { | 
            ||
| 542 | $resourcePropertyKind = $resourceProperty->getKind();  | 
            ||
| 543 |                     if ($resourcePropertyKind == ResourcePropertyKind::COMPLEX_TYPE) { | 
            ||
| 544 | $propertyValue = $this->getPropertyValue($customObject, $resourceType, $resourceProperty);  | 
            ||
| 545 | $resourceType1 = $resourceProperty->getResourceType();  | 
            ||
| 546 | $this->_writeComplexValue(  | 
            ||
| 547 | $propertyValue,  | 
            ||
| 548 | $resourceProperty->getName(),  | 
            ||
| 549 | $resourceType1,  | 
            ||
| 550 | $relativeUri . '/' . $resourceProperty->getName(),  | 
            ||
| 551 | $odataPropertyContent  | 
            ||
| 552 | );  | 
            ||
| 553 | } else if ($resourceProperty->getKind() == ResourcePropertyKind::PRIMITIVE  | 
            ||
| 554 | || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY)  | 
            ||
| 555 | || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::ETAG)  | 
            ||
| 556 | || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY | ResourcePropertyKind::ETAG)  | 
            ||
| 557 |                     ) { | 
            ||
| 558 | continue;  | 
            ||
| 559 |                     } else { | 
            ||
| 560 | $this->assert(  | 
            ||
| 561 | ($resourcePropertyKind == ResourcePropertyKind::RESOURCE_REFERENCE)  | 
            ||
| 562 | || ($resourcePropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE)  | 
            ||
| 563 | || ($resourcePropertyKind == ResourcePropertyKind::KEY_RESOURCE_REFERENCE),  | 
            ||
| 564 | '($resourcePropertyKind == ResourcePropertyKind::RESOURCE_REFERENCE)  | 
            ||
| 565 | || ($resourcePropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE)  | 
            ||
| 566 | || ($resourcePropertyKind == ResourcePropertyKind::KEY_RESOURCE_REFERENCE)'  | 
            ||
| 567 | );  | 
            ||
| 568 | |||
| 569 | $navigationProperties[$i] = new NavigationPropertyInfo($resourceProperty, $this->shouldExpandSegment($resourceProperty->getName()));  | 
            ||
| 570 |                         if ($navigationProperties[$i]->expanded) { | 
            ||
| 571 | $navigationProperties[$i]->value = $this->getPropertyValue($customObject, $resourceType, $resourceProperty);  | 
            ||
| 572 | }  | 
            ||
| 573 | |||
| 574 | $i++;  | 
            ||
| 575 | }  | 
            ||
| 576 | }  | 
            ||
| 577 | }  | 
            ||
| 578 | |||
| 579 |         } else { //This is the code path to handle projected properties of Entry | 
            ||
| 580 | $i = 0;  | 
            ||
| 581 |             foreach ($projectionNodes as $projectionNode) { | 
            ||
| 582 | $propertyName = $projectionNode->getPropertyName();  | 
            ||
| 583 | $resourceProperty = $resourceType->resolveProperty($propertyName);  | 
            ||
| 584 | $this->assert(!is_null($resourceProperty), '!is_null($resourceProperty)');  | 
            ||
| 585 | |||
| 586 |                 if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY) { | 
            ||
| 587 | $currentResourceSetWrapper2 = $this->getCurrentResourceSetWrapper();  | 
            ||
| 588 | $resourceProperties = $this->service  | 
            ||
| 589 | ->getProvidersWrapper()  | 
            ||
| 590 | ->getResourceProperties(  | 
            ||
| 591 | $currentResourceSetWrapper2,  | 
            ||
| 592 | $resourceType  | 
            ||
| 593 | );  | 
            ||
| 594 | //Check for the visibility of this navigation property  | 
            ||
| 595 |                     if (array_key_exists($resourceProperty->getName(), $resourceProperties)) { | 
            ||
| 596 | $navigationProperties[$i] = new NavigationPropertyInfo($resourceProperty, $this->shouldExpandSegment($propertyName));  | 
            ||
| 597 |                         if ($navigationProperties[$i]->expanded) { | 
            ||
| 598 | $navigationProperties[$i]->value = $this->getPropertyValue($customObject, $resourceType, $resourceProperty);  | 
            ||
| 599 | }  | 
            ||
| 600 | |||
| 601 | $i++;  | 
            ||
| 602 | continue;  | 
            ||
| 603 | }  | 
            ||
| 604 | }  | 
            ||
| 605 | |||
| 606 | //Primitve, complex or bag property  | 
            ||
| 607 | $propertyValue = $this->getPropertyValue($customObject, $resourceType, $resourceProperty);  | 
            ||
| 608 | $propertyTypeKind = $resourceProperty->getKind();  | 
            ||
| 609 | $propertyResourceType = $resourceProperty->getResourceType();  | 
            ||
| 610 | $this->assert(!is_null($propertyResourceType), '!is_null($propertyResourceType)');  | 
            ||
| 611 |                 if (ResourceProperty::sIsKindOf($propertyTypeKind, ResourcePropertyKind::BAG)) { | 
            ||
| 612 | $bagResourceType = $resourceProperty->getResourceType();  | 
            ||
| 613 | $this->_writeBagValue(  | 
            ||
| 614 | $propertyValue,  | 
            ||
| 615 | $propertyName,  | 
            ||
| 616 | $bagResourceType,  | 
            ||
| 617 | $relativeUri . '/' . $propertyName,  | 
            ||
| 618 | $odataPropertyContent  | 
            ||
| 619 | );  | 
            ||
| 620 |                 } else if (ResourceProperty::sIsKindOf($propertyTypeKind, ResourcePropertyKind::PRIMITIVE)) { | 
            ||
| 621 | $odataProperty = new ODataProperty();  | 
            ||
| 622 | $this->_writePrimitiveValue($propertyValue, $resourceProperty, $odataProperty);  | 
            ||
| 623 | $odataPropertyContent->properties[] = $odataProperty;  | 
            ||
| 624 |                 } else if ($propertyTypeKind == ResourcePropertyKind::COMPLEX_TYPE) { | 
            ||
| 625 | $complexResourceType = $resourceProperty->getResourceType();  | 
            ||
| 626 | $this->_writeComplexValue(  | 
            ||
| 627 | $propertyValue,  | 
            ||
| 628 | $propertyName,  | 
            ||
| 629 | $complexResourceType,  | 
            ||
| 630 | $relativeUri . '/' . $propertyName,  | 
            ||
| 631 | $odataPropertyContent  | 
            ||
| 632 | );  | 
            ||
| 633 |                 } else { | 
            ||
| 634 | //unexpected  | 
            ||
| 635 | $this->assert(false, '$propertyTypeKind = Primitive or Bag or ComplexType');  | 
            ||
| 636 | }  | 
            ||
| 637 | }  | 
            ||
| 638 | }  | 
            ||
| 639 | |||
| 640 |         if (!is_null($navigationProperties)) { | 
            ||
| 641 | //Write out navigation properties (deferred or inline)  | 
            ||
| 642 |             foreach ($navigationProperties as $navigationPropertyInfo) { | 
            ||
| 643 | $propertyName = $navigationPropertyInfo->resourceProperty->getName();  | 
            ||
| 644 | $type = $navigationPropertyInfo->resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE ?  | 
            ||
| 645 | 'application/atom+xml;type=entry' : 'application/atom+xml;type=feed';  | 
            ||
| 646 | $link = new ODataLink();  | 
            ||
| 647 | $link->name = ODataConstants::ODATA_RELATED_NAMESPACE . $propertyName;  | 
            ||
| 648 | $link->title = $propertyName;  | 
            ||
| 649 | $link->type = $type;  | 
            ||
| 650 | $link->url = $relativeUri . '/' . $propertyName;  | 
            ||
| 651 | |||
| 652 |                 if ($navigationPropertyInfo->expanded) { | 
            ||
| 653 | $propertyRelativeUri = $relativeUri . '/' . $propertyName;  | 
            ||
| 654 | $propertyAbsoluteUri = trim($absoluteUri, '/') . '/' . $propertyName;  | 
            ||
| 655 | $needPop = $this->pushSegmentForNavigationProperty($navigationPropertyInfo->resourceProperty);  | 
            ||
| 656 | $navigationPropertyKind = $navigationPropertyInfo->resourceProperty->getKind();  | 
            ||
| 657 | $this->assert(  | 
            ||
| 658 | $navigationPropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE  | 
            ||
| 659 | || $navigationPropertyKind == ResourcePropertyKind::RESOURCE_REFERENCE  | 
            ||
| 660 | || $navigationPropertyKind == ResourcePropertyKind::KEY_RESOURCE_REFERENCE,  | 
            ||
| 661 | '$navigationPropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE  | 
            ||
| 662 | || $navigationPropertyKind == ResourcePropertyKind::RESOURCE_REFERENCE  | 
            ||
| 663 | || $navigationPropertyKind == ResourcePropertyKind::KEY_RESOURCE_REFERENCE'  | 
            ||
| 664 | );  | 
            ||
| 665 | $currentResourceSetWrapper = $this->getCurrentResourceSetWrapper();  | 
            ||
| 666 | $this->assert(!is_null($currentResourceSetWrapper), '!is_null($currentResourceSetWrapper)');  | 
            ||
| 667 | $link->isExpanded = true;  | 
            ||
| 668 |                     if (!is_null($navigationPropertyInfo->value)) { | 
            ||
| 669 |                         if ($navigationPropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE) { | 
            ||
| 670 | $inlineFeed = new ODataFeed();  | 
            ||
| 671 | $link->isCollection = true;  | 
            ||
| 672 | $currentResourceType = $currentResourceSetWrapper->getResourceType();  | 
            ||
| 673 | $this->_writeFeedElements(  | 
            ||
| 674 | $navigationPropertyInfo->value,  | 
            ||
| 675 | $currentResourceType,  | 
            ||
| 676 | $propertyName,  | 
            ||
| 677 | $propertyAbsoluteUri,  | 
            ||
| 678 | $propertyRelativeUri,  | 
            ||
| 679 | $inlineFeed  | 
            ||
| 680 | );  | 
            ||
| 681 | $link->expandedResult = $inlineFeed;  | 
            ||
| 682 |                         } else { | 
            ||
| 683 | |||
| 684 | $link->isCollection = false;  | 
            ||
| 685 | $currentResourceType1 = $currentResourceSetWrapper->getResourceType();  | 
            ||
| 686 | |||
| 687 | $link->expandedResult = $this->_writeEntryElement(  | 
            ||
| 688 | $navigationPropertyInfo->value,  | 
            ||
| 689 | $currentResourceType1,  | 
            ||
| 690 | $propertyAbsoluteUri,  | 
            ||
| 691 | $propertyRelativeUri  | 
            ||
| 692 | );  | 
            ||
| 693 | }  | 
            ||
| 694 |                     } else { | 
            ||
| 695 | $link->expandedResult = null;  | 
            ||
| 696 | }  | 
            ||
| 697 | |||
| 698 | $this->popSegment($needPop);  | 
            ||
| 699 | }  | 
            ||
| 700 | |||
| 701 | $odataEntry->links[] = $link;  | 
            ||
| 702 | }  | 
            ||
| 703 | }  | 
            ||
| 704 | }  | 
            ||
| 705 | |||
| 706 | /**  | 
            ||
| 707 | * Writes a primitive value and related information to the given  | 
            ||
| 708 | * ODataProperty instance.  | 
            ||
| 709 | *  | 
            ||
| 710 | * @param mixed &$primitiveValue The primitive value to write.  | 
            ||
| 711 | * @param ResourceProperty &$resourceProperty The metadata of the primitive  | 
            ||
| 712 | * property value.  | 
            ||
| 713 | * @param ODataProperty &$odataProperty ODataProperty instance to which  | 
            ||
| 714 | * the primitive value and related  | 
            ||
| 715 | * information to write out.  | 
            ||
| 716 | *  | 
            ||
| 717 | * @throws ODataException If given value is not primitive.  | 
            ||
| 718 | *  | 
            ||
| 719 | * @return void  | 
            ||
| 720 | */  | 
            ||
| 721 | private function _writePrimitiveValue(&$primitiveValue,  | 
            ||
| 722 | ResourceProperty &$resourceProperty, ODataProperty &$odataProperty  | 
            ||
| 723 |     ) { | 
            ||
| 724 |         if (is_object($primitiveValue)) { | 
            ||
| 725 | //TODO ERROR: The property 'PropertyName'  | 
            ||
| 726 | //is defined as primitive type but value is an object  | 
            ||
| 727 | }  | 
            ||
| 728 | |||
| 729 | |||
| 730 | $odataProperty->name = $resourceProperty->getName();  | 
            ||
| 731 | $instanceType = $resourceProperty->getInstanceType();  | 
            ||
| 732 |         if ($instanceType instanceof ReflectionClass) { | 
            ||
| 733 | $odataProperty->typeName = $instanceType->getName();  | 
            ||
| 734 |         } else { | 
            ||
| 735 | $odataProperty->typeName = $instanceType->getFullTypeName();  | 
            ||
| 736 | }  | 
            ||
| 737 |         if (is_null($primitiveValue)) { | 
            ||
| 738 | $odataProperty->value = null;  | 
            ||
| 739 |         } else { | 
            ||
| 740 | $resourceType = $resourceProperty->getResourceType();  | 
            ||
| 741 | $this->_primitiveToString(  | 
            ||
| 742 | $resourceType,  | 
            ||
| 743 | $primitiveValue,  | 
            ||
| 744 | $odataProperty->value  | 
            ||
| 745 | );  | 
            ||
| 746 | }  | 
            ||
| 747 | }  | 
            ||
| 748 | |||
| 749 | /**  | 
            ||
| 750 | * Write value of a complex object.  | 
            ||
| 751 | *  | 
            ||
| 752 | * @param mixed &$complexValue Complex object to write.  | 
            ||
| 753 | * @param string $propertyName Name of the  | 
            ||
| 754 | * complex property  | 
            ||
| 755 | * whose value need  | 
            ||
| 756 | * to be written.  | 
            ||
| 757 | * @param ResourceType &$resourceType Expected type  | 
            ||
| 758 | * of the property.  | 
            ||
| 759 | * @param string $relativeUri Relative uri for the  | 
            ||
| 760 | * complex type element.  | 
            ||
| 761 | * @param ODataPropertyContent &$odataPropertyContent Content to write to.  | 
            ||
| 762 | *  | 
            ||
| 763 | * @return void  | 
            ||
| 764 | */  | 
            ||
| 765 | private function _writeComplexValue(&$complexValue,  | 
            ||
| 789 | }  | 
            ||
| 790 | |||
| 791 | /**  | 
            ||
| 792 | * Write value of a bag instance.  | 
            ||
| 793 | *  | 
            ||
| 794 | * @param array/NULL &$BagValue Bag value to write.  | 
            ||
| 795 | * @param string $propertyName Property name of the bag.  | 
            ||
| 796 | * @param ResourceType &$resourceType Type describing the  | 
            ||
| 797 | * bag value.  | 
            ||
| 798 | * @param string $relativeUri Relative Url to the bag.  | 
            ||
| 799 | * @param ODataPropertyContent &$odataPropertyContent On return, this object  | 
            ||
| 800 | * will hold bag value which  | 
            ||
| 801 | * can be used by writers.  | 
            ||
| 802 | *  | 
            ||
| 803 | * @return void  | 
            ||
| 804 | */  | 
            ||
| 805 | private function _writeBagValue(&$BagValue,  | 
            ||
| 849 | }  | 
            ||
| 850 | |||
| 851 | /**  | 
            ||
| 852 | * Write media resource metadata (for MLE and Named Streams)  | 
            ||
| 853 | *  | 
            ||
| 854 | * @param mixed $entryObject The entry instance being serialized.  | 
            ||
| 855 | * @param ResourceType &$resourceType Resource type of the entry instance.  | 
            ||
| 856 | * @param string $title Title for the current  | 
            ||
| 857 | * current entry instance.  | 
            ||
| 858 | * @param string $relativeUri Relative uri for the  | 
            ||
| 859 | * current entry instance.  | 
            ||
| 860 | * @param ODataEntry &$odataEntry OData entry to write to.  | 
            ||
| 861 | *  | 
            ||
| 862 | * @return void  | 
            ||
| 863 | */  | 
            ||
| 864 | private function _writeMediaResourceMetadata(  | 
            ||
| 899 | );  | 
            ||
| 900 | }  | 
            ||
| 901 | }  | 
            ||
| 902 | }  | 
            ||
| 903 | |||
| 904 | /**  | 
            ||
| 905 | * Convert the given primitive value to string.  | 
            ||
| 906 | * Note: This method will not handle null primitive value.  | 
            ||
| 907 | *  | 
            ||
| 908 | * @param ResourceType &$primtiveResourceType Type of the primitive property  | 
            ||
| 909 | * whose value need to be converted.  | 
            ||
| 910 | * @param mixed $primitiveValue Primitive value to convert.  | 
            ||
| 911 | * @param string &$stringValue On return, this parameter will  | 
            ||
| 912 | * contain converted value.  | 
            ||
| 913 | *  | 
            ||
| 914 | * @return void  | 
            ||
| 915 | */  | 
            ||
| 916 | private function _primitiveToString(ResourceType &$primtiveResourceType,  | 
            ||
| 942 | }  | 
            ||
| 943 | }  | 
            ||
| 944 | |||
| 945 | /**  | 
            ||
| 946 | * Write value of a complex object.  | 
            ||
| 947 | * Note: This method will not handle null complex value.  | 
            ||
| 948 | *  | 
            ||
| 949 | * @param mixed &$complexValue Complex object to write.  | 
            ||
| 950 | * @param string $propertyName Name of the  | 
            ||
| 951 | * complex property  | 
            ||
| 952 | * whose value  | 
            ||
| 953 | * need to be written.  | 
            ||
| 954 | * @param ResourceType &$resourceType Expected type of the  | 
            ||
| 955 | * property.  | 
            ||
| 956 | * @param string $relativeUri Relative uri for the  | 
            ||
| 957 | * complex type element.  | 
            ||
| 958 | * @param ODataPropertyContent &$odataPropertyContent Content to write to.  | 
            ||
| 959 | *  | 
            ||
| 960 | * @return ResourceType The actual type of the complex object.  | 
            ||
| 961 | *  | 
            ||
| 962 | * @return void  | 
            ||
| 963 | */  | 
            ||
| 964 | private function _complexObjectToContent(&$complexValue,  | 
            ||
| 986 | }  | 
            ||
| 987 | }  | 
            ||
| 988 |