/** * Serialize the requested resource. * * @param RequestDescription $request The description of the request submitted by the client. * @param UriProcessor $uriProcessor Reference to the uri processor. * * @return void */ protected function serializeResult(RequestDescription $request, UriProcessor $uriProcessor) { $isETagHeaderAllowed = $request->isETagHeaderAllowed(); if ($this->config->getValidateETagHeader() && !$isETagHeaderAllowed) { if (!is_null($this->_serviceHost->getRequestIfMatch()) || !is_null($this->_serviceHost->getRequestIfNoneMatch())) { throw ODataException::createBadRequestError(Messages::eTagCannotBeSpecified($this->getHost()->getAbsoluteRequestUri()->getUrlAsString())); } } $responseContentType = self::getResponseContentType($request, $uriProcessor, $this); if (is_null($responseContentType) && $request->getTargetKind() != TargetKind::MEDIA_RESOURCE()) { //the responseContentType can ONLY be null if it's a stream (media resource) and that stream is storing null as the content type throw new ODataException(Messages::unsupportedMediaType(), 415); } $odataModelInstance = null; $hasResponseBody = true; // Execution required at this point if request target to any resource other than // // (1) media resource - For Media resource 'getResponseContentType' already performed execution as it needs to know the mime type of the stream // (2) metadata - internal resource // (3) service directory - internal resource if ($request->needExecution()) { $uriProcessor->execute(); $objectModelSerializer = new ObjectModelSerializer($this, $request); if (!$request->isSingleResult()) { // Code path for collection (feed or links) $entryObjects = $request->getTargetResult(); self::assert(!is_null($entryObjects) && is_array($entryObjects), '!is_null($entryObjects) && is_array($entryObjects)'); // If related resource set is empty for an entry then we should // not throw error instead response must be empty feed or empty links if ($request->isLinkUri()) { $odataModelInstance = $objectModelSerializer->writeUrlElements($entryObjects); self::assert($odataModelInstance instanceof \POData\ObjectModel\ODataURLCollection, '$odataModelInstance instanceof ODataURLCollection'); } else { $odataModelInstance = $objectModelSerializer->writeTopLevelElements($entryObjects); self::assert($odataModelInstance instanceof \POData\ObjectModel\ODataFeed, '$odataModelInstance instanceof ODataFeed'); } } else { // Code path for entry, complex, bag, resource reference link, // primitive type or primitive value $result = $request->getTargetResult(); $requestTargetKind = $request->getTargetKind(); if ($request->isLinkUri()) { // In the query 'Orders(1245)/$links/Customer', the targeted // Customer might be null if (is_null($result)) { throw ODataException::createResourceNotFoundError($request->getIdentifier()); } $odataModelInstance = $objectModelSerializer->writeUrlElement($result); } else { if ($requestTargetKind == TargetKind::RESOURCE()) { if (!is_null($this->_serviceHost->getRequestIfMatch()) && !is_null($this->_serviceHost->getRequestIfNoneMatch())) { throw ODataException::createBadRequestError(Messages::bothIfMatchAndIfNoneMatchHeaderSpecified()); } // handle entry resource $needToSerializeResponse = true; $targetResourceType = $request->getTargetResourceType(); $eTag = $this->compareETag($result, $targetResourceType, $needToSerializeResponse); if ($needToSerializeResponse) { if (is_null($result)) { // In the query 'Orders(1245)/Customer', the targeted // Customer might be null // set status code to 204 => 'No Content' $this->_serviceHost->setResponseStatusCode(HttpStatus::CODE_NOCONTENT); $hasResponseBody = false; } else { $odataModelInstance = $objectModelSerializer->writeTopLevelElement($result); } } else { // Resource is not modified so set status code // to 304 => 'Not Modified' $this->_serviceHost->setResponseStatusCode(HttpStatus::CODE_NOT_MODIFIED); $hasResponseBody = false; } // if resource has eTagProperty then eTag header needs to written if (!is_null($eTag)) { $this->_serviceHost->setResponseETag($eTag); } } else { if ($requestTargetKind == TargetKind::COMPLEX_OBJECT()) { $odataModelInstance = $objectModelSerializer->writeTopLevelComplexObject($result, $request->getProjectedProperty()->getName(), $request->getTargetResourceType()); } else { if ($requestTargetKind == TargetKind::BAG()) { $odataModelInstance = $objectModelSerializer->writeTopLevelBagObject($result, $request->getProjectedProperty()->getName(), $request->getTargetResourceType(), $odataModelInstance); } else { if ($requestTargetKind == TargetKind::PRIMITIVE()) { $odataModelInstance = $objectModelSerializer->writeTopLevelPrimitive($result, $request->getProjectedProperty(), $odataModelInstance); } else { if ($requestTargetKind == TargetKind::PRIMITIVE_VALUE()) { // Code path for primitive value (Since its primitve no need for // object model serialization) // Customers('ANU')/CompanyName/$value => string // Employees(1)/Photo/$value => binary stream // Customers/$count => string } else { self::assert(false, 'Unexpected resource target kind'); } } } } } } } } //Note: Response content type can be null for named stream if ($hasResponseBody && !is_null($responseContentType)) { if ($request->getTargetKind() != TargetKind::MEDIA_RESOURCE() && $responseContentType != MimeTypes::MIME_APPLICATION_OCTETSTREAM) { //append charset for everything except: //stream resources as they have their own content type //binary properties (they content type will be App Octet for those...is this a good way? we could also decide based upon the projected property // $responseContentType .= ';charset=utf-8'; } } if ($hasResponseBody) { ResponseWriter::write($this, $request, $odataModelInstance, $responseContentType); } }