/** * 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(); throw ODataException::createInternalServerError($errorAsString); } if (!sqlsrv_has_rows($stmt)) { $result = null; } $result = $this->_serializeCustomer(sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)); } } else { die('Customer does not have navigation porperty with name: ' . $navigationPropName); } } 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(); throw ODataException::createInternalServerError($errorAsString); } if (!sqlsrv_has_rows($stmt)) { $result = null; } $result = $this->_serializeOrder(sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)); } } else { die('Order_Details does not have navigation porperty with name: ' . $navigationPropName); } } } return $result; }
/** * 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) && $type instanceof IType, '!is_null($type) && $type instanceof IType'); $value = null; try { //TODO #88...also this seems like dupe work $reflectionProperty = new \ReflectionProperty($entryObject, $eTagProperty->getName()); $value = $reflectionProperty->getValue($entryObject); } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::failedToAccessProperty($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::convertToOData 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; }
/** * 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 { throw ODataException::createInternalServerError('Invalid Status Code' . $value); } }
/** * Write all resource types (entity and complex types) * * @param ResourceType[] $resourceTypes resource types array * @param array $associationTypesInResourceTypesNamespace collection of * association types for the given resource types * array(string, AssociationType) * * @return void */ 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 { throw ODataException::createInternalServerError(Messages::metadataWriterExpectingEntityOrComplexResourceType()); } } } }
/** * Process the resource path and query options of client's request uri. * * @param IService $service Reference to the data service instance. * * @return URIProcessor * * @throws ODataException */ public static function process(IService $service) { $absoluteRequestUri = $service->getHost()->getAbsoluteRequestUri(); $absoluteServiceUri = $service->getHost()->getAbsoluteServiceUri(); if (!$absoluteServiceUri->isBaseOf($absoluteRequestUri)) { throw ODataException::createInternalServerError(Messages::uriProcessorRequestUriDoesNotHaveTheRightBaseUri($absoluteRequestUri->getUrlAsString(), $absoluteServiceUri->getUrlAsString())); } $uriProcessor = new UriProcessor($service); //Parse the resource path part of the request Uri. $uriProcessor->request = ResourcePathProcessor::process($service); $uriProcessor->request->setUriProcessor($uriProcessor); //Parse the query string options of the request Uri. QueryProcessor::process($uriProcessor->request, $service); return $uriProcessor; }
/** * 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) { // lion: if ($_SERVER['REQUEST_METHOD'] == HTTPRequestMethod::DELETE()) { $odataEntry = (object) array(); return; } // --- $resourceTypeKind = $resourceType->getResourceTypeKind(); if (is_null($absoluteUri) == ($resourceTypeKind == ResourceTypeKind::ENTITY)) { throw 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 corresponding // resource set is invisible). // IDSMP::getResourceProperties will give collection of properties // which are visible. $currentResourceSetWrapper1 = $this->getCurrentResourceSetWrapper(); $resourceProperties = $this->service->getProvidersWrapper()->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->properties[] = $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->resolveProperty($propertyName); $this->assert(!is_null($resourceProperty), '!is_null($resourceProperty)'); if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY) { $currentResourceSetWrapper2 = $this->getCurrentResourceSetWrapper(); $resourceProperties = $this->service->getProvidersWrapper()->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->properties[] = $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 { $link->isCollection = false; $currentResourceType1 = $currentResourceSetWrapper->getResourceType(); $link->expandedResult = $this->_writeEntryElement($navigationPropertyInfo->value, $currentResourceType1, $propertyAbsoluteUri, $propertyRelativeUri); } } else { $link->expandedResult = null; } $this->popSegment($needPop); } $odataEntry->links[] = $link; } } }
private function createNextSegment(SegmentDescriptor $previous, $segment, $checkRights) { $previousKind = $previous->getTargetKind(); if ($previousKind == TargetKind::METADATA() || $previousKind == TargetKind::BATCH() || $previousKind == TargetKind::PRIMITIVE_VALUE() || $previousKind == TargetKind::BAG() || $previousKind == TargetKind::MEDIA_RESOURCE()) { //All these targets are terminal segments, there cannot be anything after them. throw ODataException::resourceNotFoundError(Messages::segmentParserMustBeLeafSegment($previous->getIdentifier())); } $identifier = $keyPredicate = null; $this->extractSegmentIdentifierAndKeyPredicate($segment, $identifier, $keyPredicate); $hasPredicate = !is_null($keyPredicate); $current = null; if ($previousKind == TargetKind::PRIMITIVE()) { if ($identifier !== ODataConstants::URI_VALUE_SEGMENT) { throw ODataException::resourceNotFoundError(Messages::segmentParserOnlyValueSegmentAllowedAfterPrimitivePropertySegment($identifier, $previous->getIdentifier())); } $this->_assertion(!$hasPredicate); $current = SegmentDescriptor::createFrom($previous); $current->setIdentifier(ODataConstants::URI_VALUE_SEGMENT); $current->setTargetKind(TargetKind::PRIMITIVE_VALUE()); $current->setSingleResult(true); } else { if (!is_null($previous->getPrevious()) && $previous->getPrevious()->getIdentifier() === ODataConstants::URI_LINK_SEGMENT && $identifier !== ODataConstants::URI_COUNT_SEGMENT) { throw ODataException::createBadRequestError(Messages::segmentParserNoSegmentAllowedAfterPostLinkSegment($identifier)); } else { if ($previousKind == TargetKind::RESOURCE() && $previous->isSingleResult() && $identifier === ODataConstants::URI_LINK_SEGMENT) { $this->_assertion(!$hasPredicate); $current = SegmentDescriptor::createFrom($previous); $current->setIdentifier(ODataConstants::URI_LINK_SEGMENT); $current->setTargetKind(TargetKind::LINK()); } else { //Do a sanity check here if ($previousKind != TargetKind::COMPLEX_OBJECT() && $previousKind != TargetKind::RESOURCE() && $previousKind != TargetKind::LINK()) { throw ODataException::createInternalServerError(Messages::segmentParserInconsistentTargetKindState()); } if (!$previous->isSingleResult() && $identifier !== ODataConstants::URI_COUNT_SEGMENT) { throw ODataException::createBadRequestError(Messages::segmentParserCannotQueryCollection($previous->getIdentifier())); } $current = new SegmentDescriptor(); $current->setIdentifier($identifier); $current->setTargetSource(TargetSource::PROPERTY); $projectedProperty = $previous->getTargetResourceType()->resolveProperty($identifier); $current->setProjectedProperty($projectedProperty); if ($identifier === ODataConstants::URI_COUNT_SEGMENT) { if ($previousKind != TargetKind::RESOURCE()) { throw ODataException::createBadRequestError(Messages::segmentParserCountCannotBeApplied($previous->getIdentifier())); } if ($previous->isSingleResult()) { throw ODataException::createBadRequestError(Messages::segmentParserCountCannotFollowSingleton($previous->getIdentifier())); } $current->setTargetKind(TargetKind::PRIMITIVE_VALUE()); $current->setSingleResult(true); $current->setTargetResourceSetWrapper($previous->getTargetResourceSetWrapper()); $current->setTargetResourceType($previous->getTargetResourceType()); } else { if ($identifier === ODataConstants::URI_VALUE_SEGMENT && $previousKind == TargetKind::RESOURCE()) { $current->setSingleResult(true); $current->setTargetResourceType($previous->getTargetResourceType()); $current->setTargetKind(TargetKind::MEDIA_RESOURCE()); } else { if (is_null($projectedProperty)) { if (!is_null($previous->getTargetResourceType()) && !is_null($previous->getTargetResourceType()->tryResolveNamedStreamByName($identifier))) { $current->setTargetKind(TargetKind::MEDIA_RESOURCE()); $current->setSingleResult(true); $current->setTargetResourceType($previous->getTargetResourceType()); } else { throw ODataException::createResourceNotFoundError($identifier); } } else { $current->setTargetResourceType($projectedProperty->getResourceType()); $current->setSingleResult($projectedProperty->getKind() != ResourcePropertyKind::RESOURCESET_REFERENCE); if ($previousKind == TargetKind::LINK() && $projectedProperty->getTypeKind() != ResourceTypeKind::ENTITY) { throw ODataException::createBadRequestError(Messages::segmentParserLinkSegmentMustBeFollowedByEntitySegment($identifier)); } switch ($projectedProperty->getKind()) { case ResourcePropertyKind::COMPLEX_TYPE: $current->setTargetKind(TargetKind::COMPLEX_OBJECT()); break; case ResourcePropertyKind::BAG | ResourcePropertyKind::PRIMITIVE: case ResourcePropertyKind::BAG | ResourcePropertyKind::COMPLEX_TYPE: $current->setTargetKind(TargetKind::BAG()); break; case ResourcePropertyKind::RESOURCE_REFERENCE: case ResourcePropertyKind::RESOURCESET_REFERENCE: $current->setTargetKind(TargetKind::RESOURCE()); $resourceSetWrapper = $this->providerWrapper->getResourceSetWrapperForNavigationProperty($previous->getTargetResourceSetWrapper(), $previous->getTargetResourceType(), $projectedProperty); if (is_null($resourceSetWrapper)) { throw ODataException::createResourceNotFoundError($projectedProperty->getName()); } $current->setTargetResourceSetWrapper($resourceSetWrapper); break; default: if (!$projectedProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) { throw ODataException::createInternalServerError(Messages::segmentParserUnExpectedPropertyKind('Primitive')); } $current->setTargetKind(TargetKind::PRIMITIVE()); break; } if ($hasPredicate) { $this->_assertion(!$current->isSingleResult()); $keyDescriptor = $this->_createKeyDescriptor($identifier . '(' . $keyPredicate . ')', $projectedProperty->getResourceType(), $keyPredicate); $current->setKeyDescriptor($keyDescriptor); if (!$keyDescriptor->isEmpty()) { $current->setSingleResult(true); } } if ($checkRights && !is_null($current->getTargetResourceSetWrapper())) { $current->getTargetResourceSetWrapper()->checkResourceSetRightsForRead($current->isSingleResult()); } } } } } } } return $current; }
/** * 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) { throw ODataException::createBadRequestError(Messages::expandProjectionParserPropertyWithoutMatchingExpand($currentNode->getPropertyName())); } $currentNode->setSelectionFound(); $isLastSegment = $index == $subPathCount - 1; if ($selectSubPathSegment === '*') { $currentNode->setSelectAllImmediateProperties(); break; } $currentResourceType = $currentNode->getResourceType(); $resourceProperty = $currentResourceType->resolveProperty($selectSubPathSegment); if (is_null($resourceProperty)) { throw ODataException::createSyntaxError(Messages::expandProjectionParserPropertyNotFound($currentResourceType->getFullName(), $selectSubPathSegment, true)); } if (!$isLastSegment) { if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG)) { throw ODataException::createBadRequestError(Messages::expandProjectionParserBagPropertyAsInnerSelectSegment($currentResourceType->getFullName(), $selectSubPathSegment)); } else { if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) { throw ODataException::createBadRequestError(Messages::expandProjectionParserPrimitivePropertyUsedAsNavigationProperty($currentResourceType->getFullName(), $selectSubPathSegment)); } else { if ($resourceProperty->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) { throw ODataException::createBadRequestError(Messages::expandProjectionParserComplexPropertyAsInnerSelectSegment($currentResourceType->getFullName(), $selectSubPathSegment)); } else { if ($resourceProperty->getKind() != ResourcePropertyKind::RESOURCE_REFERENCE && $resourceProperty->getKind() != ResourcePropertyKind::RESOURCESET_REFERENCE) { throw ODataException::createInternalServerError(Messages::expandProjectionParserUnexpectedPropertyType()); } } } } } $node = $currentNode->findNode($selectSubPathSegment); if (is_null($node)) { if (!$isLastSegment) { throw ODataException::createBadRequestError(Messages::expandProjectionParserPropertyWithoutMatchingExpand($selectSubPathSegment)); } $node = new ProjectionNode($selectSubPathSegment, $resourceProperty); $currentNode->addNode($node); } $currentNode = $node; if ($currentNode instanceof ExpandedProjectionNode && $isLastSegment) { $currentNode->setSelectionFound(); $currentNode->markSubtreeAsSelected(); } } } }
/** * 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, ", "); }
/** * Parse and generate expression from the the given odata expression. * * * @param string $text The text expression to parse * @param ResourceType $resourceType The resource type in which * @param IExpressionProvider $expressionProvider Implementation of IExpressionProvider * * @return FilterInfo * * @throws ODataException If any error occurs while parsing the odata expression or building the php/custom expression. * */ public static function parseExpression2($text, ResourceType $resourceType, \POData\Providers\Expression\IExpressionProvider $expressionProvider) { $expressionParser2 = new ExpressionParser2($text, $resourceType, $expressionProvider instanceof PHPExpressionProvider); $expressionTree = $expressionParser2->parseFilter(); $expressionAsString = null; $expressionProvider->setResourceType($resourceType); $expressionProcessor = new ExpressionProcessor($expressionProvider); try { $expressionAsString = $expressionProcessor->processExpression($expressionTree); } catch (\InvalidArgumentException $invalidArgumentException) { throw ODataException::createInternalServerError($invalidArgumentException->getMessage()); } return new FilterInfo($expressionParser2->_navigationPropertiesUsedInTheExpression, $expressionAsString); }
/** * Get the value of a given property from an instance. * * @param mixed $entity 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 occurred while trying to access the property. * */ protected function getPropertyValue($entity, ResourceType $resourceType, ResourceProperty $resourceProperty) { try { //Is this slow? See #88 $reflectionProperty = new \ReflectionProperty($entity, $resourceProperty->getName()); return $reflectionProperty->getValue($entity); } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::objectModelSerializerFailedToAccessProperty($resourceProperty->getName(), $resourceType->getName())); } }
/** * 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)) { throw ODataException::createResourceNotFoundError($resourceSet->getName()); } // lion: if ($_SERVER['REQUEST_METHOD'] == HTTPRequestMethod::DELETE()) { return; } $entityName = $resourceSet->getResourceType()->getInstanceType()->getName(); if (!is_object($entityInstance) || !$entityInstance instanceof $entityName) { throw ODataException::createInternalServerError(Messages::providersWrapperIDSQPMethodReturnsUnExpectedType($entityName, $methodName)); } foreach ($keyDescriptor->getValidatedNamedValues() as $keyName => $valueDescription) { try { $keyProperty = new \ReflectionProperty($entityInstance, $keyName); $keyValue = $keyProperty->getValue($entityInstance); if (is_null($keyValue)) { throw ODataException::createInternalServerError(Messages::providersWrapperIDSQPMethodReturnsInstanceWithNullKeyProperties($methodName)); } $convertedValue = $valueDescription[1]->convert($valueDescription[0]); if ($keyValue != $convertedValue) { throw ODataException::createInternalServerError(Messages::providersWrapperIDSQPMethodReturnsInstanceWithNonMatchingKeys($methodName)); } } catch (\ReflectionException $reflectionException) { //throw ODataException::createInternalServerError( // Messages::orderByParserFailedToAccessOrInitializeProperty( // $resourceProperty->getName(), $resourceType->getName() // ) //); } } }
/** * 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) { throw ODataException::createInternalServerError(Messages::orderByParserUnExpectedState()); } }
/** * Build value of $skiptoken from the given object which will be the * last object in the page. * * @param mixed $lastObject entity instance from which skiptoken needs * to be built. * * @return string * * @throws ODataException If reflection exception occurs while accessing * property. */ public function buildSkipTokenValue($lastObject) { $nextPageLink = null; foreach ($this->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(); // assert($type implements IType) // If this is a string then do utf8_encode to convert // utf8 decoded characters to // corrospoding utf8 char (e.g. � to í), then do a // urlencode to convert í to %C3%AD // urlencode is needed for datetime and guid too // if ($type instanceof String || $type instanceof DateTime // || $type instanceof Guid) { // if ($type instanceof String) { // $currentObject = utf8_encode($currentObject); // } // $currentObject = urlencode($currentObject); //} // call IType::convertToOData to attach reuqired suffix // and prepfix. // e.g. $valueM, $valueF, datetime'$value', guid'$value', // '$value' etc.. // Also we can think about moving above urlencode to this // function $value = $type->convertToOData($currentObject); $nextPageLink .= $value . ', '; } } } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::internalSkipTokenInfoFailedToAccessOrInitializeProperty($subPathSegment->getName())); } $index++; } } return rtrim($nextPageLink, ", "); }
/** * Ask data service to load stream provider instance. * * @return void * * @throws ODataException */ private function _loadStreamProvider() { if (is_null($this->_streamProvider)) { $maxServiceVersion = $this->_service->getConfiguration()->getMaxDataServiceVersion(); if ($maxServiceVersion->compare(new Version(3, 0)) >= 0) { $this->_streamProvider = $this->_service->getService('IStreamProvider2'); if (!is_null($this->_streamProvider) && (!is_object($this->_streamProvider) || !$this->_streamProvider instanceof IStreamProvider2)) { throw ODataException::createInternalServerError(Messages::streamProviderWrapperInvalidStream2Instance()); } } if (is_null($this->_streamProvider)) { $this->_streamProvider = $this->_service->getService('IStreamProvider'); if (!is_null($this->_streamProvider) && (!is_object($this->_streamProvider) || !$this->_streamProvider instanceof IStreamProvider)) { throw ODataException::createInternalServerError(Messages::streamProviderWrapperInvalidStreamInstance()); } } } }