/** * Get related resource for a resource * * @param ResourceSet $sourceResourceSet The source resource set * @param mixed $sourceEntityInstance The source resource * @param ResourceSet $targetResourceSet The resource set of * the navigation property * @param ResourceProperty $targetProperty The navigation property to be * retrieved * * @return Object/null The related resource if exists else null */ public function getRelatedResourceReference(ResourceSet $sourceResourceSet, $sourceEntityInstance, ResourceSet $targetResourceSet, ResourceProperty $targetProperty) { $result = null; $srcClass = get_class($sourceEntityInstance); $navigationPropName = $targetProperty->getName(); if ($srcClass === 'Order') { if ($navigationPropName === 'Customer') { if (empty($sourceEntityInstance->CustomerID)) { $result = null; } else { $query = "SELECT * FROM Customers WHERE CustomerID = '{$sourceEntityInstance->CustomerID}'"; $stmt = sqlsrv_query($this->_connectionHandle, $query); if ($stmt === false) { $errorAsString = self::_getSQLSRVError(); ODataException::createInternalServerError($errorAsString); } if (!sqlsrv_has_rows($stmt)) { $result = null; } $result = $this->_serializeCustomer(sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)); } } else { ODataException::createInternalServerError('Customer does not have navigation porperty with name: ' . $navigationPropName . ' Contact Service Provider'); } } else { if ($srcClass === 'Order_Details') { if ($navigationPropName === 'Order') { if (empty($sourceEntityInstance->OrderID)) { $result = null; } else { $query = "SELECT * FROM Orders WHERE OrderID = {$sourceEntityInstance->OrderID}"; $stmt = sqlsrv_query($this->_connectionHandle, $query); if ($stmt === false) { $errorAsString = self::_getSQLSRVError(); ODataException::createInternalServerError($errorAsString); } if (!sqlsrv_has_rows($stmt)) { $result = null; } $result = $this->_serializeOrder(sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)); } } else { ODataException::createInternalServerError('Order_Details does not have navigation porperty with name: ' . $navigationPropName . ' Contact Service Provider'); } } } return $result; }
/** * Build nextpage link from the given object which will be the last object * in the page. * * @param mixed $lastObject Entity instance to build next page link from. * * @return string * * @throws ODataException If reflection exception occurs while accessing * property. */ public function buildNextPageLink($lastObject) { $nextPageLink = null; foreach ($this->_internalOrderByInfo->getOrderByPathSegments() as $orderByPathSegment) { $index = 0; $currentObject = $lastObject; $subPathSegments = $orderByPathSegment->getSubPathSegments(); $subPathCount = count($subPathSegments); foreach ($subPathSegments as &$subPathSegment) { $isLastSegment = $index == $subPathCount - 1; try { $dummyProperty = new \ReflectionProperty($currentObject, $subPathSegment->getName()); $currentObject = $dummyProperty->getValue($currentObject); if (is_null($currentObject)) { $nextPageLink .= 'null, '; break; } else { if ($isLastSegment) { $type = $subPathSegment->getInstanceType(); $value = $type->convertToOData($currentObject); $nextPageLink .= $value . ', '; } } } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::internalSkipTokenInfoFailedToAccessOrInitializeProperty($subPathSegment->getName())); } $index++; } } return rtrim($nextPageLink, ", "); }
/** * Write all resource types (entity and complex types) * * @param array $resourceTypes resource types array * array(ResourceType) * @param array $associationTypesInResourceTypesNamespace collection of * association types for the given resource types * array(string, AssociationType) * * @return nothing */ private function _writeResourceTypes($resourceTypes, $associationTypesInResourceTypesNamespace) { foreach ($resourceTypes as $resourceType) { if ($resourceType->getResourceTypeKind() == ResourceTypeKind::ENTITY) { $this->_writeEntityType($resourceType, $associationTypesInResourceTypesNamespace); } else { if ($resourceType->getResourceTypeKind() == ResourceTypeKind::COMPLEX) { $this->_writeComplexType($resourceType); } else { ODataException::createInternalServerError(Messages::metadataWriterExpectingEntityOrComplexResourceType()); } } } }
/** * Returns the etag for the given resource. * Note: This function will not add W\" prefix and " suffix, its callers * repsonsability. * * @param mixed &$entryObject Resource for which etag value needs to * be returned * @param ResourceType &$resourceType Resource type of the $entryObject * * @return string/NULL ETag value for the given resource (with values encoded * for use in a URI) there are etag properties, NULL if * there is no etag property. */ protected function getETagForEntry(&$entryObject, ResourceType &$resourceType) { $eTag = null; $comma = null; foreach ($resourceType->getETagProperties() as $eTagProperty) { $type = $eTagProperty->getInstanceType(); self::assert(!is_null($type) && array_search('ODataProducer\\Providers\\Metadata\\Type\\IType', class_implements($type)) !== false, '!is_null($type) && array_search(\'ODataProducer\\Providers\\Metadata\\Type\\IType\', class_implements($type)) !== false'); $value = null; try { $reflectionProperty = new \ReflectionProperty($entryObject, $eTagProperty->getName()); $value = $reflectionProperty->getValue($entryObject); } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::dataServiceFailedToAccessProperty($eTagProperty->getName(), $resourceType->getName())); } if (is_null($value)) { $eTag = $eTag . $comma . 'null'; } else { $eTag = $eTag . $comma . $type->convertToOData($value); } $comma = ','; } if (!is_null($eTag)) { // If eTag is made up of datetime or string properties then the above // IType::converToOData will perform utf8 and url encode. But we don't // want this for eTag value. $eTag = urldecode(utf8_decode($eTag)); return rtrim($eTag, ','); } return null; }
/** * Write values of properties of given entry (resource) or complex object. * * @param mixed $customObject Entity or complex object * with properties * to write out. * @param ResourceType &$resourceType Resource type describing * the metadata of * the custom object. * @param string $absoluteUri Absolute uri for the given * entry object * NULL for complex object. * @param string $relativeUri Relative uri for the given * custom object. * @param ODataEntry &$odataEntry ODataEntry instance to * place links and * expansion of the * entry object, * NULL for complex object. * @param ODataPropertyContent &$odataPropertyContent ODataPropertyContent * instance in which * to place the values. * * @return void */ private function _writeObjectProperties($customObject, ResourceType &$resourceType, $absoluteUri, $relativeUri, &$odataEntry, ODataPropertyContent &$odataPropertyContent) { $resourceTypeKind = $resourceType->getResourceTypeKind(); if (is_null($absoluteUri) == ($resourceTypeKind == ResourceTypeKind::ENTITY)) { ODataException::createInternalServerError(Messages::badProviderInconsistentEntityOrComplexTypeUsage($resourceType->getName())); } $this->assert($resourceTypeKind == ResourceTypeKind::ENTITY && $odataEntry instanceof ODataEntry || $resourceTypeKind == ResourceTypeKind::COMPLEX && is_null($odataEntry), '(($resourceTypeKind == ResourceTypeKind::ENTITY) && ($odataEntry instanceof ODataEntry)) || (($resourceTypeKind == ResourceTypeKind::COMPLEX) && is_null($odataEntry))'); $projectionNodes = null; $navigationProperties = null; if ($resourceTypeKind == ResourceTypeKind::ENTITY) { $projectionNodes = $this->getProjectionNodes(); $navigationProperties = array(); } if (is_null($projectionNodes)) { //This is the code path to handle properties of Complex type //or Entry without projection (i.e. no expansion or selection) $resourceProperties = array(); if ($resourceTypeKind == ResourceTypeKind::ENTITY) { // If custom object is an entry then it can contain navigation // properties which are invisible (because the corrosponding // resource set is invisible). // IDSMP::getResourceProperties will give collection of properties // which are visible. $currentResourceSetWrapper1 = $this->getCurrentResourceSetWrapper(); $resourceProperties = $this->dataService->getMetadataQueryProviderWrapper()->getResourceProperties($currentResourceSetWrapper1, $resourceType); } else { $resourceProperties = $resourceType->getAllProperties(); } //First write out primitve types foreach ($resourceProperties as $name => $resourceProperty) { if ($resourceProperty->getKind() == ResourcePropertyKind::PRIMITIVE || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY) || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::ETAG) || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY | ResourcePropertyKind::ETAG)) { $odataProperty = new ODataProperty(); $primitiveValue = $this->getPropertyValue($customObject, $resourceType, $resourceProperty); $this->_writePrimitiveValue($primitiveValue, $resourceProperty, $odataProperty); $odataPropertyContent->odataProperty[] = $odataProperty; } } //Write out bag and complex type $i = 0; foreach ($resourceProperties as $resourceProperty) { if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG)) { //Handle Bag Property (Bag of Primitive or complex) $propertyValue = $this->getPropertyValue($customObject, $resourceType, $resourceProperty); $resourceType2 = $resourceProperty->getResourceType(); $this->_writeBagValue($propertyValue, $resourceProperty->getName(), $resourceType2, $relativeUri . '/' . $resourceProperty->getName(), $odataPropertyContent); } else { $resourcePropertyKind = $resourceProperty->getKind(); if ($resourcePropertyKind == ResourcePropertyKind::COMPLEX_TYPE) { $propertyValue = $this->getPropertyValue($customObject, $resourceType, $resourceProperty); $resourceType1 = $resourceProperty->getResourceType(); $this->_writeComplexValue($propertyValue, $resourceProperty->getName(), $resourceType1, $relativeUri . '/' . $resourceProperty->getName(), $odataPropertyContent); } else { if ($resourceProperty->getKind() == ResourcePropertyKind::PRIMITIVE || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY) || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::ETAG) || $resourceProperty->getKind() == (ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY | ResourcePropertyKind::ETAG)) { continue; } else { $this->assert($resourcePropertyKind == ResourcePropertyKind::RESOURCE_REFERENCE || $resourcePropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE, '($resourcePropertyKind == ResourcePropertyKind::RESOURCE_REFERENCE) || ($resourcePropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE)'); $navigationProperties[$i] = new NavigationPropertyInfo($resourceProperty, $this->shouldExpandSegment($resourceProperty->getName())); if ($navigationProperties[$i]->expanded) { $navigationProperties[$i]->value = $this->getPropertyValue($customObject, $resourceType, $resourceProperty); } $i++; } } } } } else { //This is the code path to handle projected properties of Entry $i = 0; foreach ($projectionNodes as $projectionNode) { $propertyName = $projectionNode->getPropertyName(); $resourceProperty = $resourceType->tryResolvePropertyTypeByName($propertyName); $this->assert(!is_null($resourceProperty), '!is_null($resourceProperty)'); if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY) { $currentResourceSetWrapper2 = $this->getCurrentResourceSetWrapper(); $resourceProperties = $this->dataService->getMetadataQueryProviderWrapper()->getResourceProperties($currentResourceSetWrapper2, $resourceType); //Check for the visibility of this navigation property if (array_key_exists($resourceProperty->getName(), $resourceProperties)) { $navigationProperties[$i] = new NavigationPropertyInfo($resourceProperty, $this->shouldExpandSegment($propertyName)); if ($navigationProperties[$i]->expanded) { $navigationProperties[$i]->value = $this->getPropertyValue($customObject, $resourceType, $resourceProperty); } $i++; continue; } } //Primitve, complex or bag property $propertyValue = $this->getPropertyValue($customObject, $resourceType, $resourceProperty); $propertyTypeKind = $resourceProperty->getKind(); $propertyResourceType = $resourceProperty->getResourceType(); $this->assert(!is_null($propertyResourceType), '!is_null($propertyResourceType)'); if (ResourceProperty::sIsKindOf($propertyTypeKind, ResourcePropertyKind::BAG)) { $bagResourceType = $resourceProperty->getResourceType(); $this->_writeBagValue($propertyValue, $propertyName, $bagResourceType, $relativeUri . '/' . $propertyName, $odataPropertyContent); } else { if (ResourceProperty::sIsKindOf($propertyTypeKind, ResourcePropertyKind::PRIMITIVE)) { $odataProperty = new ODataProperty(); $this->_writePrimitiveValue($propertyValue, $resourceProperty, $odataProperty); $odataPropertyContent->odataProperty[] = $odataProperty; } else { if ($propertyTypeKind == ResourcePropertyKind::COMPLEX_TYPE) { $complexResourceType = $resourceProperty->getResourceType(); $this->_writeComplexValue($propertyValue, $propertyName, $complexResourceType, $relativeUri . '/' . $propertyName, $odataPropertyContent); } else { //unexpected $this->assert(false, '$propertyTypeKind = Primitive or Bag or ComplexType'); } } } } } if (!is_null($navigationProperties)) { //Write out navigation properties (deferred or inline) foreach ($navigationProperties as $navigationPropertyInfo) { $propertyName = $navigationPropertyInfo->resourceProperty->getName(); $type = $navigationPropertyInfo->resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE ? 'application/atom+xml;type=entry' : 'application/atom+xml;type=feed'; $link = new ODataLink(); $link->name = ODataConstants::ODATA_RELATED_NAMESPACE . $propertyName; $link->title = $propertyName; $link->type = $type; $link->url = $relativeUri . '/' . $propertyName; if ($navigationPropertyInfo->expanded) { $propertyRelativeUri = $relativeUri . '/' . $propertyName; $propertyAbsoluteUri = trim($absoluteUri, '/') . '/' . $propertyName; $needPop = $this->pushSegmentForNavigationProperty($navigationPropertyInfo->resourceProperty); $navigationPropertyKind = $navigationPropertyInfo->resourceProperty->getKind(); $this->assert($navigationPropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE || $navigationPropertyKind == ResourcePropertyKind::RESOURCE_REFERENCE, '$navigationPropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE || $navigationPropertyKind == ResourcePropertyKind::RESOURCE_REFERENCE'); $currentResourceSetWrapper = $this->getCurrentResourceSetWrapper(); $this->assert(!is_null($currentResourceSetWrapper), '!is_null($currentResourceSetWrapper)'); $link->isExpanded = true; if (!is_null($navigationPropertyInfo->value)) { if ($navigationPropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE) { $inlineFeed = new ODataFeed(); $link->isCollection = true; $currentResourceType = $currentResourceSetWrapper->getResourceType(); $this->_writeFeedElements($navigationPropertyInfo->value, $currentResourceType, $propertyName, $propertyAbsoluteUri, $propertyRelativeUri, $inlineFeed); $link->expandedResult = $inlineFeed; } else { $inlineEntry = new ODataEntry(); $link->isCollection = false; $currentResourceType1 = $currentResourceSetWrapper->getResourceType(); $this->_writeEntryElement($navigationPropertyInfo->value, $currentResourceType1, $propertyAbsoluteUri, $propertyRelativeUri, $inlineEntry); $link->expandedResult = $inlineEntry; } } else { $link->expandedResult = null; } $this->popSegment($needPop); } $odataEntry->links[] = $link; } } }
/** * Validate the given entity instance. * * @param object $entityInstance Entity instance to validate * @param ResourceSet &$resourceSet Resource set to which the entity * instance belongs to. * @param KeyDescriptor &$keyDescriptor The key descriptor. * @param string $methodName Method from which this function * invoked. * * @return void * * @throws ODataException */ private function _validateEntityInstance($entityInstance, ResourceSet &$resourceSet, KeyDescriptor &$keyDescriptor, $methodName) { if (is_null($entityInstance)) { ODataException::createResourceNotFoundError($resourceSet->getName()); } $entityName = $resourceSet->getResourceType()->getInstanceType()->getName(); if (!is_object($entityInstance) || !$entityInstance instanceof $entityName) { ODataException::createInternalServerError(Messages::metadataQueryProviderWrapperIDSQPMethodReturnsUnExpectedType($entityName, $methodName)); } foreach ($keyDescriptor->getValidatedNamedValues() as $keyName => $valueDescription) { try { $keyProperty = new \ReflectionProperty($entityInstance, $keyName); $keyValue = $keyProperty->getValue($entityInstance); if (is_null($keyValue)) { ODataException::createInternalServerError(Messages::metadataQueryProviderWrapperIDSQPMethodReturnsInstanceWithNullKeyProperties($methodName)); } $convertedValue = $valueDescription[1]->convert($valueDescription[0]); if ($keyValue != $convertedValue) { ODataException::createInternalServerError(Messages::metadataQueryProviderWrapperIDSQPMethodReturnsInstanceWithNonMatchingKeys($methodName)); } } catch (\ReflectionException $reflectionException) { //throw ODataException::createInternalServerError( // Messages::orderByParserFailedToAccessOrInitializeProperty( // $resourceProperty->getName(), $resourceType->getName() // ) //); } } }
/** * Parse and generate PHP or custom (using custom expression provider) expression * from the the given odata expression. * * @param string $text The text expression to parse * @param ResourceType $resourceType The resource type in which * expression will be applied * @param IExpressionProvider $expressionProvider Implementation of IExpressionProvider * if developer is using IDSQP2, null * in-case of IDSQP which falls to default * expression provider that is PHP expression * provider * * @return InternalFilterInfo * * @throws ODataException If any error occurs while parsing the odata * expression or building the php/custom expression. */ public static function parseExpression2($text, ResourceType $resourceType, $expressionProvider) { $isCustomExpressionProvider = !is_null($expressionProvider); $expressionParser2 = new ExpressionParser2($text, $resourceType, $isCustomExpressionProvider); $expressionTree = null; try { $expressionTree = $expressionParser2->parseFilter(); } catch (ODataException $odataException) { throw $odataException; } $expressionProcessor = null; $expressionAsString = null; $filterFunction = null; if (!$isCustomExpressionProvider) { $expressionProvider = new PHPExpressionProvider('$lt'); } $expressionProvider->setResourceType($resourceType); $expressionProcessor = new ExpressionProcessor($expressionTree, $expressionProvider); try { $expressionAsString = $expressionProcessor->processExpression(); } catch (\InvalidArgumentException $invalidArgumentException) { ODataException::createInternalServerError($invalidArgumentException->getMessage()); } $navigationPropertiesUsed = empty($expressionParser2->_navigationPropertiesUsedInTheExpression) ? null : $expressionParser2->_navigationPropertiesUsedInTheExpression; unset($expressionProcessor); unset($expressionParser2); if ($isCustomExpressionProvider) { $filterFunction = new AnonymousFunction(array(), ' ODataException::createInternalServerError("Library will not perform filtering in case of custom IExpressionProvider"); '); } else { $filterFunction = new AnonymousFunction(array('$lt'), 'if(' . $expressionAsString . ') { return true; } else { return false;}'); } return new InternalFilterInfo(new FilterInfo($navigationPropertiesUsed), $filterFunction, $expressionAsString, $isCustomExpressionProvider); }
/** * Process the resource path and query options of client's request uri. * * @param DataService &$dataService Reference to the data service instance. * * @return void * * @throws ODataException */ public static function process(DataService &$dataService) { $absoluteRequestUri = $dataService->getHost()->getAbsoluteRequestUri(); $absoluteServiceUri = $dataService->getHost()->getAbsoluteServiceUri(); if (!$absoluteServiceUri->isBaseOf($absoluteRequestUri)) { ODataException::createInternalServerError(Messages::uriProcessorRequestUriDoesNotHaveTheRightBaseUri($absoluteRequestUri->getUrlAsString(), $absoluteServiceUri->getUrlAsString())); } $uriProcessor = new UriProcessor($dataService); //Parse the resource path part of the request Uri. try { $uriProcessor->_requestDescription = ResourcePathProcessor::process($absoluteRequestUri, $dataService); $uriProcessor->_requestDescription->setUriProcessor($uriProcessor); } catch (ODataException $odataException) { throw $odataException; } //Parse the query string options of the request Uri. try { QueryProcessor::process($uriProcessor->_requestDescription, $dataService); } catch (ODataException $odataException) { throw $odataException; } return $uriProcessor; }
/** * Create SegmentDescriptors for a set of given segments, optionally * check for rights. * * @param array(string) $segments String array of segments to parse * @param boolean $checkRights Whether to check for rights or not * * @return void * * @throws ODataException Exception incase of any error found while * precessing segments */ private function _createSegmentDescriptors($segments, $checkRights) { if (empty($segments)) { $this->_segmentDescriptors[] = new SegmentDescriptor(); $this->_segmentDescriptors[0]->setTargetKind(RequestTargetKind::SERVICE_DIRECTORY); return; } $segmentCount = count($segments); $identifier = $keyPredicate = null; $this->_extractSegmentIdentifierAndKeyPredicate($segments[0], $identifier, $keyPredicate); $this->_segmentDescriptors[] = $this->_createFirstSegmentDescriptor($identifier, $keyPredicate, $checkRights); $previous = $this->_segmentDescriptors[0]; for ($i = 1; $i < $segmentCount; $i++) { if ($previous->getTargetKind() == RequestTargetKind::METADATA || $previous->getTargetKind() == RequestTargetKind::BATCH || $previous->getTargetKind() == RequestTargetKind::PRIMITIVE_VALUE || $previous->getTargetKind() == RequestTargetKind::BAG || $previous->getTargetKind() == RequestTargetKind::MEDIA_RESOURCE) { ODataException::resourceNotFoundError(Messages::segmentParserMustBeLeafSegment($previous->getIdentifier())); } $identifier = $keyPredicate = null; $this->_extractSegmentIdentifierAndKeyPredicate($segments[$i], $identifier, $keyPredicate); $hasPredicate = !is_null($keyPredicate); $descriptor = null; if ($previous->getTargetKind() == RequestTargetKind::PRIMITIVE) { if ($identifier !== ODataConstants::URI_VALUE_SEGMENT) { ODataException::resourceNotFoundError(Messages::segmentParserOnlyValueSegmentAllowedAfterPrimitivePropertySegment($identifier, $previous->getIdentifier())); } $this->_assertion(!$hasPredicate); $descriptor = SegmentDescriptor::createFrom($previous); $descriptor->setIdentifier(ODataConstants::URI_VALUE_SEGMENT); $descriptor->setTargetKind(RequestTargetKind::PRIMITIVE_VALUE); $descriptor->setSingleResult(true); } else { if (!is_null($previous->getPrevious()) && $previous->getPrevious()->getIdentifier() === ODataConstants::URI_LINK_SEGMENT && $identifier !== ODataConstants::URI_COUNT_SEGMENT) { ODataException::createBadRequestError(Messages::segmentParserNoSegmentAllowedAfterPostLinkSegment($identifier)); } else { if ($previous->getTargetKind() == RequestTargetKind::RESOURCE && $previous->isSingleResult() && $identifier === ODataConstants::URI_LINK_SEGMENT) { $this->_assertion(!$hasPredicate); $descriptor = SegmentDescriptor::createFrom($previous); $descriptor->setIdentifier(ODataConstants::URI_LINK_SEGMENT); $descriptor->setTargetKind(RequestTargetKind::LINK); } else { //Do a sanity check here if ($previous->getTargetKind() != RequestTargetKind::COMPLEX_OBJECT && $previous->getTargetKind() != RequestTargetKind::RESOURCE && $previous->getTargetKind() != RequestTargetKind::LINK) { ODataException::createInternalServerError(Messages::segmentParserInconsistentTargetKindState()); } if (!$previous->isSingleResult() && $identifier !== ODataConstants::URI_COUNT_SEGMENT) { ODataException::createBadRequestError(Messages::segmentParserCannotQueryCollection($previous->getIdentifier())); } $descriptor = new SegmentDescriptor(); $descriptor->setIdentifier($identifier); $descriptor->setTargetSource(RequestTargetSource::PROPERTY); $projectedProperty = $previous->getTargetResourceType()->tryResolvePropertyTypeByName($identifier); $descriptor->setProjectedProperty($projectedProperty); if ($identifier === ODataConstants::URI_COUNT_SEGMENT) { if ($previous->getTargetKind() != RequestTargetKind::RESOURCE) { ODataException::createBadRequestError(Messages::segmentParserCountCannotBeApplied($previous->getIdentifier())); } if ($previous->isSingleResult()) { ODataException::createBadRequestError(Messages::segmentParserCountCannotFollowSingleton($previous->getIdentifier())); } $descriptor->setTargetKind(RequestTargetKind::PRIMITIVE_VALUE); $descriptor->setSingleResult(true); $descriptor->setTargetResourceSetWrapper($previous->getTargetResourceSetWrapper()); $descriptor->setTargetResourceType($previous->getTargetResourceType()); } else { if ($identifier === ODataConstants::URI_VALUE_SEGMENT && $previous->getTargetKind() == RequestTargetKind::RESOURCE) { $descriptor->setSingleResult(true); $descriptor->setTargetResourceType($previous->getTargetResourceType()); $descriptor->setTargetKind(RequestTargetKind::MEDIA_RESOURCE); } else { if (is_null($projectedProperty)) { if (!is_null($previous->getTargetResourceType()) && !is_null($previous->getTargetResourceType()->tryResolveNamedStreamByName($identifier))) { $descriptor->setTargetKind(RequestTargetKind::MEDIA_RESOURCE); $descriptor->setSingleResult(true); $descriptor->setTargetResourceType($previous->getTargetResourceType()); } else { ODataException::createResourceNotFoundError($identifier); } } else { $descriptor->setTargetResourceType($projectedProperty->getResourceType()); $descriptor->setSingleResult($projectedProperty->getKind() != ResourcePropertyKind::RESOURCESET_REFERENCE); if ($previous->getTargetKind() == RequestTargetKind::LINK && $projectedProperty->getTypeKind() != ResourceTypeKind::ENTITY) { ODataException::createBadRequestError(Messages::segmentParserLinkSegmentMustBeFollowedByEntitySegment($identifier)); } switch ($projectedProperty->getKind()) { case ResourcePropertyKind::COMPLEX_TYPE: $descriptor->setTargetKind(RequestTargetKind::COMPLEX_OBJECT); break; case ResourcePropertyKind::BAG | ResourcePropertyKind::PRIMITIVE: case ResourcePropertyKind::BAG | ResourcePropertyKind::COMPLEX_TYPE: $descriptor->setTargetKind(RequestTargetKind::BAG); break; case ResourcePropertyKind::RESOURCE_REFERENCE: case ResourcePropertyKind::RESOURCESET_REFERENCE: $descriptor->setTargetKind(RequestTargetKind::RESOURCE); $resourceSetWrapper = $this->_providerWrapper->getResourceSetWrapperForNavigationProperty($previous->getTargetResourceSetWrapper(), $previous->getTargetResourceType(), $projectedProperty); if (is_null($resourceSetWrapper)) { ODataException::createResourceNotFoundError($projectedProperty->getName()); } $descriptor->setTargetResourceSetWrapper($resourceSetWrapper); break; default: if (!$projectedProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) { ODataException::createInternalServerError(Messages::segmentParserUnExpectedPropertyKind('Primitive')); } $descriptor->setTargetKind(RequestTargetKind::PRIMITIVE); break; } if ($hasPredicate) { $this->_assertion(!$descriptor->isSingleResult()); $keyDescriptor = $this->_createKeyDescriptor($identifier . '(' . $keyPredicate . ')', $projectedProperty->getResourceType(), $keyPredicate); $descriptor->setKeyDescriptor($keyDescriptor); if (!$keyDescriptor->isEmpty()) { $descriptor->setSingleResult(true); } } if ($checkRights && !is_null($descriptor->getTargetResourceSetWrapper())) { $descriptor->getTargetResourceSetWrapper()->checkResourceSetRightsForRead($descriptor->isSingleResult()); } } } } } } } $descriptor->setPrevious($previous); $previous->setNext($descriptor); $this->_segmentDescriptors[] = $descriptor; $previous = $descriptor; } if ($previous->getTargetKind() == RequestTargetKind::LINK) { ODataException::createBadRequestError(Messages::segmentParserMissingSegmentAfterLink()); } }
/** * Get the value of a given property from an instance. * * @param mixed &$object Instance of a type which * contains this property. * @param ResourceType &$resourceType Resource type instance * containing metadata about * the instance. * @param ResourceProperty &$resourceProperty Resource property instance * containing metadata about the * property whose value * to be retrieved. * * @return mixed The value of the given property. * * @throws ODataException If reflection exception occured * while trying to access the property. */ protected function getPropertyValue(&$object, ResourceType &$resourceType, ResourceProperty &$resourceProperty) { try { $reflectionProperty = new \ReflectionProperty($object, $resourceProperty->getName()); $propertyValue = $reflectionProperty->getValue($object); return $propertyValue; } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::objectModelSerializerFailedToAccessProperty($resourceProperty->getName(), $resourceType->getName())); } }
/** * Modify the 'Projection Tree' to include selection details * * @param array(array(string)) $selectPathSegments Collection of select * paths. * * @return void * * @throws ODataException If any error occurs while processing select * path segments */ private function _applySelectionToProjectionTree($selectPathSegments) { foreach ($selectPathSegments as $selectSubPathSegments) { $currentNode = $this->_rootProjectionNode; $subPathCount = count($selectSubPathSegments); foreach ($selectSubPathSegments as $index => $selectSubPathSegment) { if (!$currentNode instanceof RootProjectionNode && !$currentNode instanceof ExpandedProjectionNode) { ODataException::createBadRequestError(Messages::expandProjectionParserPropertyWithoutMatchingExpand($currentNode->getPropertyName())); } $currentNode->setSelectionFound(); $isLastSegment = $index == $subPathCount - 1; if ($selectSubPathSegment === '*') { $currentNode->setSelectAllImmediateProperties(); break; } $currentResourceType = $currentNode->getResourceType(); $resourceProperty = $currentResourceType->tryResolvePropertyTypeByName($selectSubPathSegment); if (is_null($resourceProperty)) { ODataException::createSyntaxError(Messages::expandProjectionParserPropertyNotFound($currentResourceType->getFullName(), $selectSubPathSegment, true)); } if (!$isLastSegment) { if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG)) { ODataException::createBadRequestError(Messages::expandProjectionParserBagPropertyAsInnerSelectSegment($currentResourceType->getFullName(), $selectSubPathSegment)); } else { if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) { ODataException::createBadRequestError(Messages::expandProjectionParserPrimitivePropertyUsedAsNavigationProperty($currentResourceType->getFullName(), $selectSubPathSegment)); } else { if ($resourceProperty->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) { ODataException::createBadRequestError(Messages::expandProjectionParserComplexPropertyAsInnerSelectSegment($currentResourceType->getFullName(), $selectSubPathSegment)); } else { if ($resourceProperty->getKind() != ResourcePropertyKind::RESOURCE_REFERENCE && $resourceProperty->getKind() != ResourcePropertyKind::RESOURCESET_REFERENCE) { ODataException::createInternalServerError(Messages::expandProjectionParserUnexpectedPropertyType()); } } } } } $node = $currentNode->findNode($selectSubPathSegment); if (is_null($node)) { if (!$isLastSegment) { ODataException::createBadRequestError(Messages::expandProjectionParserPropertyWithoutMatchingExpand($selectSubPathSegment)); } $node = new ProjectionNode($selectSubPathSegment, $resourceProperty); $currentNode->addNode($node); } $currentNode = $node; if ($currentNode instanceof ExpandedProjectionNode && $isLastSegment) { $currentNode->setSelectionFound(); $currentNode->markSubtreeAsSelected(); } } } }
/** * Assert that the given condition is true, if false throw * ODataException for unexpected state * * @param boolean $condition The condition to assert * * @return void * * @throws ODataException */ private function _assertion($condition) { if (!$condition) { ODataException::createInternalServerError(Messages::orderByParserUnExpectedState()); } }
/** * Sets the value status code header on the response * * @param string $value The status code * * @return void */ public function setResponseStatusCode($value) { $floor = floor($value / 100); if ($floor >= 1 && $floor <= 5) { $statusDescription = HttpStatus::getStatusDescription($value); if (!is_null($statusDescription)) { $statusDescription = ' ' . $statusDescription; } $this->_operationContext->outgoingResponse()->setStatusCode($value . $statusDescription); } else { ODataException::createInternalServerError('Invalid Status Code' . $value); } }
/** * Ask data service to load stream provider instance. * * @return void * * @throws ODataException */ private function _loadStreamProvider() { if (is_null($this->_streamProvider)) { $maxServiceVersion = $this->_dataService->getServiceConfiguration()->getMaxDataServiceVersionObject(); if ($maxServiceVersion->compare(new Version(3, 0)) >= 0) { $this->_streamProvider = $this->_dataService->getService('IDataServiceStreamProvider2'); if (!is_null($this->_streamProvider) && (!is_object($this->_streamProvider) || array_search('ODataProducer\\Providers\\Stream\\IDataServiceStreamProvider2', class_implements($this->_streamProvider)) === false)) { ODataException::createInternalServerError(Messages::dataServiceStreamProviderWrapperInvalidStream2Instance()); } } if (is_null($this->_streamProvider)) { $this->_streamProvider = $this->_dataService->getService('IDataServiceStreamProvider'); if (!is_null($this->_streamProvider) && (!is_object($this->_streamProvider) || array_search('ODataProducer\\Providers\\Stream\\IDataServiceStreamProvider', class_implements($this->_streamProvider)) === false)) { ODataException::createInternalServerError(Messages::dataServiceStreamProviderWrapperInvalidStreamInstance()); } } } }