/** * Process the $expand and $select option and update the request description. * * @return void * * @throws ODataException Throws bad request error in the following cases * (1) If $expand or select cannot be applied to the * requested resource. * (2) If projection is disabled by the developer * (3) If some error occurs while parsing the options */ private function _processExpandAndSelect() { $expand = $this->_dataService->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_EXPAND); if (!is_null($expand)) { $this->_checkExpandOrSelectApplicable(ODataConstants::HTTPQUERY_STRING_EXPAND); } $select = $this->_dataService->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SELECT); if (!is_null($select)) { if (!$this->_dataService->getServiceConfiguration()->getAcceptProjectionRequests()) { ODataException::createBadRequestError(Messages::dataServiceConfigurationProjectionsNotAccepted()); } $this->_checkExpandOrSelectApplicable(ODataConstants::HTTPQUERY_STRING_SELECT); } // We will generate RootProjectionNode in case of $link request also, but // expand and select in this case must be null (we are ensuring this above) // 'RootProjectionNode' is required while generating next page Link if ($this->_expandSelectApplicable || $this->_requestDescription->isLinkUri()) { try { $rootProjectionNode = ExpandProjectionParser::parseExpandAndSelectClause($this->_requestDescription->getTargetResourceSetWrapper(), $this->_requestDescription->getTargetResourceType(), $this->_requestDescription->getInternalOrderByInfo(), $this->_requestDescription->getSkipCount(), $this->_requestDescription->getTopCount(), $expand, $select, $this->_dataService->getMetadataQueryProviderWrapper()); if ($rootProjectionNode->isSelectionSpecified()) { $this->_requestDescription->raiseMinimumVersionRequirement(2, 0, $this->_dataService); } if ($rootProjectionNode->hasPagedExpandedResult()) { $this->_requestDescription->raiseResponseVersion(2, 0, $this->_dataService); } $this->_requestDescription->setRootProjectionNode($rootProjectionNode); } catch (ODataException $odataException) { throw $odataException; } } }
/** * Write in specific format * * @param DataService &$dataService Dataservice * @param RequestDescription &$requestDescription Request description object * @param Object &$odataModelInstance OData model instance * @param String $responseContentType Content type of the response * @param String $responseFormat Output format * * @return nothing */ public static function write(DataService &$dataService, RequestDescription &$requestDescription, &$odataModelInstance, $responseContentType, $responseFormat) { $responseBody = null; $dataServiceVersion = $requestDescription->getResponseDataServiceVersion(); if ($responseFormat == ResponseFormat::METADATA_DOCUMENT) { // /$metadata $writer = new MetadataWriter($dataService->getMetadataQueryProviderWrapper()); $responseBody = $writer->writeMetadata(); $dataServiceVersion = $writer->getDataServiceVersion(); } else { if ($responseFormat == ResponseFormat::TEXT) { // /Customer('ALFKI')/CompanyName/$value // /Customers/$count $responseBody = utf8_encode($requestDescription->getTargetResult()); } else { if ($responseFormat == ResponseFormat::BINARY) { // Binary property or media resource $targetKind = $requestDescription->getTargetKind(); if ($targetKind == RequestTargetKind::MEDIA_RESOURCE) { $eTag = $dataService->getStreamProvider()->getStreamETag($requestDescription->getTargetResult(), $requestDescription->getResourceStreamInfo()); $dataService->getHost()->setResponseETag($eTag); $responseBody = $dataService->getStreamProvider()->getReadStream($requestDescription->getTargetResult(), $requestDescription->getResourceStreamInfo()); } else { $responseBody = $requestDescription->getTargetResult(); } if (is_null($responseContentType)) { $responseContentType = ODataConstants::MIME_APPLICATION_OCTETSTREAM; } } else { $writer = null; $absoluteServiceUri = $dataService->getHost()->getAbsoluteServiceUri()->getUrlAsString(); if ($responseFormat == ResponseFormat::ATOM || $responseFormat == ResponseFormat::PLAIN_XML) { if (is_null($odataModelInstance)) { $writer = new \ODataProducer\Writers\ServiceDocument\Atom\ServiceDocumentWriter($dataService->getMetadataQueryProviderWrapper(), $absoluteServiceUri); } else { $isPostV1 = $requestDescription->getResponseDataServiceVersion()->compare(new Version(1, 0)) == 1; $writer = new ODataWriter($absoluteServiceUri, $isPostV1, 'atom'); } } else { if ($responseFormat == ResponseFormat::JSON) { if (is_null($odataModelInstance)) { $writer = new \ODataProducer\Writers\ServiceDocument\Json\ServiceDocumentWriter($dataService->getMetadataQueryProviderWrapper(), $absoluteServiceUri); } else { $isPostV1 = $requestDescription->getResponseDataServiceVersion()->compare(new Version(1, 0)) == 1; $writer = new ODataWriter($absoluteServiceUri, $isPostV1, 'json'); } } } $responseBody = $writer->writeRequest($odataModelInstance); } } } $dataService->getHost()->setResponseStatusCode(HttpStatus::CODE_OK); $dataService->getHost()->setResponseContentType($responseContentType); $dataService->getHost()->setResponseVersion($dataServiceVersion->toString() . ';'); $dataService->getHost()->setResponseCacheControl(ODataConstants::HTTPRESPONSE_HEADER_CACHECONTROL_NOCACHE); $dataService->getHost()->getWebOperationContext()->outgoingResponse()->setStream($responseBody); }
/** * Process the given request Uri and creates an instance of * RequestDescription from the processed uri. * * @param Url &$absoluteRequestUri The absolute request uri. * @param DataService &$dataService Reference to the data service * instance. * * @return RequestDescription * * @throws ODataException If any exception occurs while processing the segments * or incase of any version incompatibility. */ public static function process(Url &$absoluteRequestUri, DataService &$dataService) { $absoluteRequestUri = $dataService->getHost()->getAbsoluteRequestUri(); $absoluteServiceUri = $dataService->getHost()->getAbsoluteServiceUri(); $requestUriSegments = array_slice($absoluteRequestUri->getSegments(), $absoluteServiceUri->getSegmentCount()); $segmentDescriptors = null; try { $segmentDescriptors = SegmentParser::parseRequestUriSegements($requestUriSegments, $dataService->getMetadataQueryProviderWrapper(), true); } catch (ODataException $odataException) { throw $odataException; } $requestDescription = new RequestDescription($segmentDescriptors, $absoluteRequestUri); $requestTargetKind = $requestDescription->getTargetKind(); if ($requestTargetKind != RequestTargetKind::METADATA && $requestTargetKind != RequestTargetKind::BATCH && $requestTargetKind != RequestTargetKind::SERVICE_DIRECTORY) { if ($requestTargetKind != RequestTargetKind::PRIMITIVE_VALUE && $requestTargetKind != RequestTargetKind::MEDIA_RESOURCE) { $requestDescription->setContainerName($requestDescription->getIdentifier()); } else { // http://odata/NW.svc/Orders/$count // http://odata/NW.svc/Orders(123)/Customer/CustomerID/$value // http://odata/NW.svc/Employees(1)/$value // http://odata/NW.svc/Employees(1)/ThumbNail_48X48/$value $requestDescription->setContainerName($segmentDescriptors[count($segmentDescriptors) - 2]->getIdentifier()); } if ($requestDescription->getIdentifier() === ODataConstants::URI_COUNT_SEGMENT) { if (!$dataService->getServiceConfiguration()->getAcceptCountRequests()) { ODataException::createBadRequestError(Messages::dataServiceConfigurationCountNotAccepted()); } $requestDescription->setRequestCountOption(RequestCountOption::VALUE_ONLY); // use of $count requires request DataServiceVersion // and MaxDataServiceVersion // greater than or equal to 2.0 $requestDescription->raiseResponseVersion(2, 0, $dataService); $requestDescription->raiseMinimumVersionRequirement(2, 0, $dataService); } else { if ($requestDescription->isNamedStream()) { $requestDescription->raiseMinimumVersionRequirement(3, 0, $dataService); } else { if ($requestDescription->getTargetKind() == RequestTargetKind::RESOURCE) { if (!$requestDescription->isLinkUri()) { $resourceSetWrapper = $requestDescription->getTargetResourceSetWrapper(); //assert($resourceSetWrapper != null) $hasNamedStream = $resourceSetWrapper->hasNamedStreams($dataService->getMetadataQueryProviderWrapper()); $hasBagProperty = $resourceSetWrapper->hasBagProperty($dataService->getMetadataQueryProviderWrapper()); if ($hasNamedStream || $hasBagProperty) { $requestDescription->raiseResponseVersion(3, 0, $dataService); } } } else { if ($requestDescription->getTargetKind() == RequestTargetKind::BAG) { $requestDescription->raiseResponseVersion(3, 0, $dataService); } } } } } return $requestDescription; }
/** * Pushes a segment for the current navigation property being written out. * Note: Refer 'ObjectModelSerializerNotes.txt' for more details about * 'Segment Stack' and this method. * Note: Calls to this method should be balanced with calls to popSegment. * * @param ResourceProperty &$resourceProperty Current navigation property * being written out * * @return true if a segment was pushed, false otherwise * * @throws InvalidOperationException If this function invoked with non-navigation * property instance. */ private function _pushSegmentForNavigationProperty(ResourceProperty &$resourceProperty) { if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY) { $this->assert(!empty($this->_segmentNames), '!is_empty($this->_segmentNames'); $currentResourceSetWrapper = $this->_getCurrentResourceSetWrapper(); $currentResourceType = $currentResourceSetWrapper->getResourceType(); $currentResourceSetWrapper = $this->_dataService->getMetadataQueryProviderWrapper()->getResourceSetWrapperForNavigationProperty($currentResourceSetWrapper, $currentResourceType, $resourceProperty); $this->assert(!is_null($currentResourceSetWrapper), '!null($currentResourceSetWrapper)'); return $this->_pushSegment($resourceProperty->getName(), $currentResourceSetWrapper); } else { throw new InvalidOperationException('pushSegmentForNavigationProperty should not be called with non-entity type'); } }