Пример #1
0
 /**
  * Process the request Uri and creates an instance of
  * RequestDescription from the processed uri.
  * 
  * @param IService $service        Reference to the data service instance.
  *
  * @return RequestDescription
  * 
  * @throws ODataException If any exception occurs while processing the segments
  *                        or in case of any version incompatibility.
  */
 public static function process(IService $service)
 {
     $host = $service->getHost();
     $absoluteRequestUri = $host->getAbsoluteRequestUri();
     $absoluteServiceUri = $host->getAbsoluteServiceUri();
     $requestUriSegments = array_slice($absoluteRequestUri->getSegments(), $absoluteServiceUri->getSegmentCount());
     $segments = SegmentParser::parseRequestUriSegments($requestUriSegments, $service->getProvidersWrapper(), true);
     $request = new RequestDescription($segments, $absoluteRequestUri, $service->getConfiguration()->getMaxDataServiceVersion(), $host->getRequestVersion(), $host->getRequestMaxVersion());
     $kind = $request->getTargetKind();
     if ($kind == TargetKind::METADATA() || $kind == TargetKind::BATCH() || $kind == TargetKind::SERVICE_DIRECTORY()) {
         return $request;
     }
     if ($kind == TargetKind::PRIMITIVE_VALUE() || $kind == TargetKind::MEDIA_RESOURCE()) {
         // 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
         $request->setContainerName($segments[count($segments) - 2]->getIdentifier());
     } else {
         $request->setContainerName($request->getIdentifier());
     }
     if ($request->getIdentifier() === ODataConstants::URI_COUNT_SEGMENT) {
         if (!$service->getConfiguration()->getAcceptCountRequests()) {
             throw ODataException::createBadRequestError(Messages::configurationCountNotAccepted());
         }
         $request->queryType = QueryType::COUNT();
         // use of $count requires request DataServiceVersion
         // and MaxDataServiceVersion greater than or equal to 2.0
         $request->raiseResponseVersion(2, 0);
         $request->raiseMinVersionRequirement(2, 0);
     } else {
         if ($request->isNamedStream()) {
             $request->raiseMinVersionRequirement(3, 0);
         } else {
             if ($request->getTargetKind() == TargetKind::RESOURCE()) {
                 if (!$request->isLinkUri()) {
                     $resourceSetWrapper = $request->getTargetResourceSetWrapper();
                     //assert($resourceSetWrapper != null)
                     $hasNamedStream = $resourceSetWrapper->hasNamedStreams($service->getProvidersWrapper());
                     $hasBagProperty = $resourceSetWrapper->hasBagProperty($service->getProvidersWrapper());
                     if ($hasNamedStream || $hasBagProperty) {
                         $request->raiseResponseVersion(3, 0);
                     }
                 }
             } else {
                 if ($request->getTargetKind() == TargetKind::BAG()) {
                     $request->raiseResponseVersion(3, 0);
                 }
             }
         }
     }
     return $request;
 }
Пример #2
0
 /**
  * Checks whether etag headers are allowed for this request.
  * 
  * @return boolean True if ETag header (If-Match or If-NoneMatch)
  *                 is allowed for the request, False otherwise.
  */
 public function isETagHeaderAllowed()
 {
     return $this->lastSegment->isSingleResult() && $this->queryType != QueryType::COUNT() && !$this->isLinkUri() && (is_null($this->_rootProjectionNode) || !$this->_rootProjectionNode->isExpansionSpecified());
 }
Пример #3
0
 /**
  * Write top level url collection.
  * 
  * @param array $entryObjects Array of entry resources
  * whose url to be written.
  * 
  * @return ODataURLCollection
  */
 public function writeUrlElements($entryObjects)
 {
     $urls = new ODataURLCollection();
     if (!empty($entryObjects)) {
         $i = 0;
         foreach ($entryObjects as $entryObject) {
             $urls->urls[$i] = $this->writeUrlElement($entryObject);
             $i++;
         }
         if ($i > 0 && $this->needNextPageLink(count($entryObjects))) {
             $urls->nextPageLink = $this->getNextLinkUri($entryObjects[$i - 1], $this->request->getRequestUrl()->getUrlAsString());
         }
     }
     if ($this->request->queryType == QueryType::ENTITIES_WITH_COUNT()) {
         $urls->count = $this->request->getCountValue();
     }
     return $urls;
 }
Пример #4
0
 /**
  * Execute queries for expansion.
  * 
  * @param array(mixed)/mixed $result Resource(s) whose navigation properties needs to be expanded.
  *
  *
  * @return void
  */
 private function _executeExpansion($result)
 {
     $expandedProjectionNodes = $this->_getExpandedProjectionNodes();
     foreach ($expandedProjectionNodes as $expandedProjectionNode) {
         $isCollection = $expandedProjectionNode->getResourceProperty()->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE;
         $expandedPropertyName = $expandedProjectionNode->getResourceProperty()->getName();
         if (is_array($result)) {
             foreach ($result as $entry) {
                 // Check for null entry
                 if ($isCollection) {
                     $currentResourceSet = $this->_getCurrentResourceSetWrapper()->getResourceSet();
                     $resourceSetOfProjectedProperty = $expandedProjectionNode->getResourceSetWrapper()->getResourceSet();
                     $projectedProperty1 = $expandedProjectionNode->getResourceProperty();
                     $result1 = $this->providers->getRelatedResourceSet(QueryType::ENTITIES(), $currentResourceSet, $entry, $resourceSetOfProjectedProperty, $projectedProperty1, null, null, null, null)->results;
                     if (!empty($result1)) {
                         $internalOrderByInfo = $expandedProjectionNode->getInternalOrderByInfo();
                         if (!is_null($internalOrderByInfo)) {
                             $orderByFunction = $internalOrderByInfo->getSorterFunction()->getReference();
                             usort($result1, $orderByFunction);
                             unset($internalOrderByInfo);
                             $takeCount = $expandedProjectionNode->getTakeCount();
                             if (!is_null($takeCount)) {
                                 $result1 = array_slice($result1, 0, $takeCount);
                             }
                         }
                         $entry->{$expandedPropertyName} = $result1;
                         $projectedProperty = $expandedProjectionNode->getResourceProperty();
                         $needPop = $this->_pushSegmentForNavigationProperty($projectedProperty);
                         $this->_executeExpansion($result1);
                         $this->_popSegment($needPop);
                     } else {
                         $entry->{$expandedPropertyName} = array();
                     }
                 } else {
                     $currentResourceSet1 = $this->_getCurrentResourceSetWrapper()->getResourceSet();
                     $resourceSetOfProjectedProperty1 = $expandedProjectionNode->getResourceSetWrapper()->getResourceSet();
                     $projectedProperty2 = $expandedProjectionNode->getResourceProperty();
                     $result1 = $this->providers->getRelatedResourceReference($currentResourceSet1, $entry, $resourceSetOfProjectedProperty1, $projectedProperty2);
                     $entry->{$expandedPropertyName} = $result1;
                     if (!is_null($result1)) {
                         $projectedProperty3 = $expandedProjectionNode->getResourceProperty();
                         $needPop = $this->_pushSegmentForNavigationProperty($projectedProperty3);
                         $this->_executeExpansion($result1);
                         $this->_popSegment($needPop);
                     }
                 }
             }
         } else {
             if ($isCollection) {
                 $currentResourceSet2 = $this->_getCurrentResourceSetWrapper()->getResourceSet();
                 $resourceSetOfProjectedProperty2 = $expandedProjectionNode->getResourceSetWrapper()->getResourceSet();
                 $projectedProperty4 = $expandedProjectionNode->getResourceProperty();
                 $result1 = $this->providers->getRelatedResourceSet(QueryType::ENTITIES(), $currentResourceSet2, $result, $resourceSetOfProjectedProperty2, $projectedProperty4, null, null, null, null)->results;
                 if (!empty($result1)) {
                     $internalOrderByInfo = $expandedProjectionNode->getInternalOrderByInfo();
                     if (!is_null($internalOrderByInfo)) {
                         $orderByFunction = $internalOrderByInfo->getSorterFunction()->getReference();
                         usort($result1, $orderByFunction);
                         unset($internalOrderByInfo);
                         $takeCount = $expandedProjectionNode->getTakeCount();
                         if (!is_null($takeCount)) {
                             $result1 = array_slice($result1, 0, $takeCount);
                         }
                     }
                     $result->{$expandedPropertyName} = $result1;
                     $projectedProperty7 = $expandedProjectionNode->getResourceProperty();
                     $needPop = $this->_pushSegmentForNavigationProperty($projectedProperty7);
                     $this->_executeExpansion($result1);
                     $this->_popSegment($needPop);
                 } else {
                     $result->{$expandedPropertyName} = array();
                 }
             } else {
                 $currentResourceSet3 = $this->_getCurrentResourceSetWrapper()->getResourceSet();
                 $resourceSetOfProjectedProperty3 = $expandedProjectionNode->getResourceSetWrapper()->getResourceSet();
                 $projectedProperty5 = $expandedProjectionNode->getResourceProperty();
                 $result1 = $this->providers->getRelatedResourceReference($currentResourceSet3, $result, $resourceSetOfProjectedProperty3, $projectedProperty5);
                 $result->{$expandedPropertyName} = $result1;
                 if (!is_null($result1)) {
                     $projectedProperty6 = $expandedProjectionNode->getResourceProperty();
                     $needPop = $this->_pushSegmentForNavigationProperty($projectedProperty6);
                     $this->_executeExpansion($result1);
                     $this->_popSegment($needPop);
                 }
             }
         }
     }
 }
Пример #5
0
 public function testGetRelatedResourceSetReturnsArrayWhenQueryTypeIsEntitiesWithCount()
 {
     $orderBy = null;
     $top = 10;
     $skip = 10;
     $fakeQueryResult = new QueryResult();
     $fakeQueryResult->count = 4;
     $fakeQueryResult->results = null;
     //null is not an array
     $fakeSourceEntity = new \stdClass();
     Phockito::when($this->mockQueryProvider->getRelatedResourceSet(QueryType::ENTITIES_WITH_COUNT(), $this->mockResourceSet, $fakeSourceEntity, $this->mockResourceSet2, $this->mockResourceProperty, $this->mockFilterInfo, $orderBy, $top, $skip))->return($fakeQueryResult);
     $wrapper = $this->getMockedWrapper();
     try {
         $wrapper->getRelatedResourceSet(QueryType::ENTITIES_WITH_COUNT(), $this->mockResourceSet, $fakeSourceEntity, $this->mockResourceSet2, $this->mockResourceProperty, $this->mockFilterInfo, $orderBy, $top, $skip);
         $this->fail("expected exception not thrown");
     } catch (ODataException $ex) {
         $this->assertEquals(Messages::queryProviderResultsMissing("IQueryProvider::getRelatedResourceSet", QueryType::ENTITIES_WITH_COUNT()), $ex->getMessage());
         $this->assertEquals(500, $ex->getStatusCode());
     }
 }
Пример #6
0
 /**
  * For queries like http://localhost/NorthWind.svc/Customers
  */
 public function getResourceSet(QueryType $queryType, ResourceSet $resourceSet, $filterInfo = null, $orderBy = null, $top = null, $skip = null)
 {
     $result = new QueryResult();
     $entityClassName = $resourceSet->getResourceType()->getInstanceType()->name;
     $entityName = $this->getEntityName($entityClassName);
     $tableName = $this->getTableName($entityName);
     $option = null;
     if ($queryType == QueryType::ENTITIES_WITH_COUNT()) {
         //tell mysql we want to know the count prior to the LIMIT
         //$option = 'SQL_CALC_FOUND_ROWS';
     }
     $where = $filterInfo ? ' WHERE ' . $filterInfo->getExpressionAsString() : '';
     $order = $orderBy ? ' ORDER BY ' . $this->getOrderByExpressionAsString($orderBy) : '';
     $sqlCount = 'SELECT COUNT(*) FROM ' . $tableName . $where;
     if ($queryType == QueryType::ENTITIES() || $queryType == QueryType::ENTITIES_WITH_COUNT()) {
         $sql = 'SELECT ' . $option . ' * FROM ' . $tableName . $where . $order . ($top ? ' LIMIT ' . $top : '') . ($skip ? ' OFFSET ' . $skip : '');
         $data = $this->queryAll($sql);
         if ($queryType == QueryType::ENTITIES_WITH_COUNT()) {
             //get those found rows
             //$result->count = $this->queryScalar('SELECT FOUND_ROWS()');
             $result->count = $this->queryScalar($sqlCount);
         }
         $result->results = array_map($entityClassName . '::fromRecord', $data);
     } elseif ($queryType == QueryType::COUNT()) {
         $result->count = QueryResult::adjustCountForPaging($this->queryScalar($sqlCount), $top, $skip);
     }
     return $result;
 }
Пример #7
0
 public function testProcessRequestForCollectionWithInlineCountProviderHandlesPaging()
 {
     $requestURI = new Url('http://host.com/data.svc/Collection/?$inlinecount=allpages');
     Phockito::when($this->mockServiceHost->getAbsoluteRequestUri())->return($requestURI);
     //mock inline count as all pages
     Phockito::when($this->mockServiceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_INLINECOUNT))->return("allpages");
     $this->fakeServiceConfig->setAcceptCountRequests(true);
     $this->fakeServiceConfig->setMaxDataServiceVersion(ProtocolVersion::V2());
     $uriProcessor = UriProcessor::process($this->mockService);
     $fakeQueryResult = new QueryResult();
     $fakeQueryResult->results = array(1, 2, 3);
     $fakeQueryResult->count = 10;
     Phockito::when($this->mockProvidersWrapper->getResourceSet(QueryType::ENTITIES_WITH_COUNT(), $this->mockCollectionResourceSetWrapper, null, null, null, null))->return($fakeQueryResult);
     //indicate that the Provider performs the paging (thus it will use the count in the QueryResult)
     Phockito::when($this->mockProvidersWrapper->handlesOrderedPaging())->return(true);
     $uriProcessor->execute();
     $request = $uriProcessor->getRequest();
     $actual = $request->getTargetResult();
     $this->assertEquals(array(1, 2, 3), $actual);
     $this->assertEquals(10, $request->getCountValue());
 }
Пример #8
0
 /**
  * Process the $inlinecount option and update the request description.
  *
  * @return void
  * 
  * @throws ODataException Throws bad request error in the following cases
  *                          (1) If $inlinecount is disabled by the developer
  *                          (2) If both $count and $inlinecount specified
  *                          (3) If $inlinecount value is unknown
  *                          (4) If capability negotiation over version fails
  */
 private function _processCount()
 {
     $inlineCount = $this->service->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_INLINECOUNT);
     //If it's not specified, we're done
     if (is_null($inlineCount)) {
         return;
     }
     //If the service doesn't allow count requests..then throw an exception
     if (!$this->service->getConfiguration()->getAcceptCountRequests()) {
         throw ODataException::createBadRequestError(Messages::configurationCountNotAccepted());
     }
     $inlineCount = trim($inlineCount);
     //if it's set to none, we don't do inline counts
     if ($inlineCount === ODataConstants::URI_ROWCOUNT_OFFOPTION) {
         return;
     }
     //You can't specify $count & $inlinecount together
     //TODO: ensure there's a test for this case see #55
     if ($this->request->queryType == QueryType::COUNT()) {
         throw ODataException::createBadRequestError(Messages::queryProcessorInlineCountWithValueCount());
     }
     $this->_checkSetQueryApplicable();
     //TODO: why do we do this check?
     if ($inlineCount === ODataConstants::URI_ROWCOUNT_ALLOPTION) {
         $this->request->queryType = QueryType::ENTITIES_WITH_COUNT();
         $this->request->raiseMinVersionRequirement(2, 0);
         $this->request->raiseResponseVersion(2, 0);
     } else {
         throw ODataException::createBadRequestError(Messages::queryProcessorInvalidInlineCountOptionError());
     }
 }
Пример #9
0
 private function ValidateQueryResult($queryResult, QueryType $queryType, $methodName)
 {
     if (!$queryResult instanceof QueryResult) {
         throw ODataException::createInternalServerError(Messages::queryProviderReturnsNonQueryResult($methodName));
     }
     if ($queryType == QueryType::COUNT() || $queryType == QueryType::ENTITIES_WITH_COUNT()) {
         //and the provider is supposed to handle the ordered paging they must return a count!
         if ($this->queryProvider->handlesOrderedPaging() && !is_numeric($queryResult->count)) {
             throw ODataException::createInternalServerError(Messages::queryProviderResultCountMissing($methodName, $queryType));
         }
         //If POData is supposed to handle the ordered aging they must return results! (possibly empty)
         if (!$this->queryProvider->handlesOrderedPaging() && !is_array($queryResult->results)) {
             throw ODataException::createInternalServerError(Messages::queryProviderResultsMissing($methodName, $queryType));
         }
     }
     if (($queryType == QueryType::ENTITIES() || $queryType == QueryType::ENTITIES_WITH_COUNT()) && !is_array($queryResult->results)) {
         throw ODataException::createInternalServerError(Messages::queryProviderResultsMissing($methodName, $queryType));
     }
 }