/** * Applies the query options to the resource(s) retrieved from the data source. * * @param SegmentDescriptor $segment The descriptor which holds resource(s) on which query options to be applied. * */ private function applyQueryOptions(SegmentDescriptor $segment) { //TODO: I'm not really happy with this..i think i'd rather keep the result the QueryResult //not even bother with the setCountValue stuff (shouldn't counts be on segments?) //and just work with the QueryResult in the object model serializer $result = $segment->getResult(); if (!$result instanceof QueryResult) { //If the segment isn't a query result, then there's no paging or counting to be done return; } // Note $inlinecount=allpages means include the total count regardless of paging..so we set the counts first // regardless if POData does the paging or not. if ($this->request->queryType == QueryType::ENTITIES_WITH_COUNT()) { if ($this->providers->handlesOrderedPaging()) { $this->request->setCountValue($result->count); } else { $this->request->setCountValue(count($result->results)); } } //Have POData perform paging if necessary if (!$this->providers->handlesOrderedPaging() && !empty($result->results)) { $result->results = $this->performPaging($result->results); } //a bit surprising, but $skip and $top affects $count so update it here, not above //IE data.svc/Collection/$count?$top=10 returns 10 even if Collection has 11+ entries if ($this->request->queryType == QueryType::COUNT()) { if ($this->providers->handlesOrderedPaging()) { $this->request->setCountValue($result->count); } else { $this->request->setCountValue(count($result->results)); } } $segment->setResult($result->results); }
/** * 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; }
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()); } }
/** * 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; }
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()); }
/** * 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()); } }
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)); } }