/** * Gets the namespace of the given resource type, * if it is null, then default to the container namespace. * * @param ResourceType $resourceType The resource type * * @return string The namespace of the resource type. */ protected function getResourceTypeNamespace(ResourceType $resourceType) { $resourceTypeNamespace = $resourceType->getNamespace(); if (empty($resourceTypeNamespace)) { $resourceTypeNamespace = $this->providersWrapper->getContainerNamespace(); } return $resourceTypeNamespace; }
/** * Test search InternalSkipTokenInfo::GetIndexOfFirstEntryInNextPage function */ public function testGetIndexOfFirstEntryInNextPage2() { $this->markTestSkipped("Skipped because it depends on a query provider that isn't mocked"); $northWindMetadata = NorthWindMetadata::Create(); $configuration = new ServiceConfiguration($northWindMetadata); $configuration->setEntitySetAccessRule('*', EntitySetRights::ALL); $providersWrapper = new ProvidersWrapper($northWindMetadata, $this->mockQueryProvider, $configuration); $resourceSetWrapper = $providersWrapper->resolveResourceSet('Orders'); $resourceType = $resourceSetWrapper->getResourceType(); $orderBy = 'ShipName asc, Freight'; //Note: library will add prim key as last sort key $orderBy .= ', OrderID'; $qp = new NorthWindQueryProvider1(); $orders = $qp->getResourceSet($resourceSetWrapper->getResourceSet()); $internalOrderByInfo = OrderByParser::parseOrderByClause($resourceSetWrapper, $resourceType, $orderBy, $providersWrapper); $compFun = $internalOrderByInfo->getSorterFunction(); $fun = $compFun->getReference(); usort($orders, $fun); $numRecords = count($orders); //----------------------------------------------------------------- //Search with a key that exactly matches $skipToken = utf8_decode(urldecode("'Antonio%20Moreno%20Taquer%C3%ADa',22.0000M,10365")); $skipToken = urldecode($skipToken); $internalSkipTokenInfo = SkipTokenParser::parseSkipTokenClause($resourceType, $internalOrderByInfo, $skipToken); $nextIndex = $internalSkipTokenInfo->getIndexOfFirstEntryInTheNextPage($orders); $this->assertTrue($nextIndex > 1); $this->assertTrue($nextIndex < $numRecords); //$nextIndex is the index of order record next to the searched record $this->assertEquals($orders[$nextIndex - 1]->OrderID, 10365); $this->assertEquals($orders[$nextIndex - 1]->Freight, 22.0); //----------------------------------------------------------------- //Search with a key that partially matches, in the DB there is no //order with ShipName 'An', but there are records start with //'An', so partial match, since its a parial match other two //key wont be used for comparsion $skipToken = "'An',22.0000M,10365"; $internalSkipTokenInfo = SkipTokenParser::parseSkipTokenClause($resourceType, $internalOrderByInfo, $skipToken); $nextIndex = $internalSkipTokenInfo->getIndexOfFirstEntryInTheNextPage($orders); $this->assertTrue($nextIndex > 1); $this->assertTrue($nextIndex < $numRecords); //Make sure this is the most matching record by comparing with previous record $prevOrder = $orders[$nextIndex - 1]; $r = strcmp($prevOrder->ShipName, $orders[$nextIndex]->ShipName); $this->assertTrue($r < 0); //Make sure this is the most matching record by comparing with next record $nextOrder = $orders[$nextIndex + 1]; $r = strcmp($nextOrder->ShipName, $orders[$nextIndex]->ShipName); $this->assertTrue($r >= 0); //----------------------------------------------------------------- //Search with a key that does not exists $skipToken = "'XXX',11,10365"; $internalSkipTokenInfo = SkipTokenParser::parseSkipTokenClause($resourceType, $internalOrderByInfo, $skipToken); $nextIndex = $internalSkipTokenInfo->getIndexOfFirstEntryInTheNextPage($orders); $this->assertTrue($nextIndex == -1); //----------------------------------------------------------------- }
public function testWriteMetadata() { $northWindMetadata = NorthWindMetadata::Create(); $configuration = new ServiceConfiguration($northWindMetadata); $configuration->setEntitySetAccessRule("*", EntitySetRights::ALL); $configuration->setMaxDataServiceVersion(ProtocolVersion::V3()); $providersWrapper = new ProvidersWrapper($northWindMetadata, $this->mockQueryProvider, $configuration, false); $metadataWriter = new MetadataWriter($providersWrapper); $metadata = $metadataWriter->writeMetadata(); $this->assertNotNull($metadata); $this->assertEquals($providersWrapper->getContainerName(), 'NorthWindEntities'); $this->assertEquals($providersWrapper->getContainerNamespace(), 'NorthWind'); $this->assertStringStartsWith('<edmx:Edmx Version="1.0"', $metadata); $customerResourceSet = $providersWrapper->resolveResourceSet('Customers'); $this->assertEquals($customerResourceSet->getName(), 'Customers'); $this->assertEquals($customerResourceSet->getResourceType()->getName(), 'Customer'); $customerEntityType = $providersWrapper->resolveResourceType('Customer'); $this->assertEquals($customerEntityType->getResourceTypeKind(), ResourceTypeKind::ENTITY); }
/** * Write entity container * * @return void */ private function _writeEntityContainer() { $this->_xmlWriter->startElement(ODataConstants::ENTITY_CONTAINER); $this->_xmlWriter->writeAttribute(ODataConstants::NAME, $this->providersWrapper->getContainerName()); $this->_xmlWriter->writeAttributeNs(ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX, ODataConstants::ISDEFAULT_ENTITY_CONTAINER_ATTRIBUTE, null, "true"); foreach ($this->_metadataManager->getResourceSets() as $resourceSet) { $this->_xmlWriter->startElement(ODataConstants::ENTITY_SET); $this->_xmlWriter->writeAttribute(ODataConstants::NAME, $resourceSet->getName()); $this->_xmlWriter->writeAttribute(ODataConstants::ENTITY_TYPE, $resourceSet->getResourceType()->getFullName()); $this->_xmlWriter->endElement(); } $this->_writeAssociationSets(); $this->_xmlWriter->endElement(); }
/** * Build 'Projection Tree' from the given expand path segments * * @param array(array(string)) $expandPathSegments Collection of expand paths. * * * @return void * * @throws ODataException If any error occurs while processing the expand path segments * . */ private function _buildProjectionTree($expandPathSegments) { foreach ($expandPathSegments as $expandSubPathSegments) { $currentNode = $this->_rootProjectionNode; foreach ($expandSubPathSegments as $expandSubPathSegment) { $resourceSetWrapper = $currentNode->getResourceSetWrapper(); $resourceType = $currentNode->getResourceType(); $resourceProperty = $resourceType->resolveProperty($expandSubPathSegment); if (is_null($resourceProperty)) { throw ODataException::createSyntaxError(Messages::expandProjectionParserPropertyNotFound($resourceType->getFullName(), $expandSubPathSegment, false)); } else { if ($resourceProperty->getTypeKind() != ResourceTypeKind::ENTITY) { throw ODataException::createBadRequestError(Messages::expandProjectionParserExpandCanOnlyAppliedToEntity($resourceType->getFullName(), $expandSubPathSegment)); } } $resourceSetWrapper = $this->_providerWrapper->getResourceSetWrapperForNavigationProperty($resourceSetWrapper, $resourceType, $resourceProperty); if (is_null($resourceSetWrapper)) { throw ODataException::createBadRequestError(Messages::badRequestInvalidPropertyNameSpecified($resourceType->getFullName(), $expandSubPathSegment)); } $singleResult = $resourceProperty->isKindOf(ResourcePropertyKind::RESOURCE_REFERENCE); $resourceSetWrapper->checkResourceSetRightsForRead($singleResult); $pageSize = $resourceSetWrapper->getResourceSetPageSize(); $internalOrderByInfo = null; if ($pageSize != 0 && !$singleResult) { $this->_rootProjectionNode->setPagedExpandedResult(true); $rt = $resourceSetWrapper->getResourceType(); //assert($rt != null) $keys = array_keys($rt->getKeyProperties()); //assert(!empty($keys)) $orderBy = null; foreach ($keys as $key) { $orderBy = $orderBy . $key . ', '; } $orderBy = rtrim($orderBy, ', '); $internalOrderByInfo = OrderByParser::parseOrderByClause($resourceSetWrapper, $rt, $orderBy, $this->_providerWrapper); } $node = $currentNode->findNode($expandSubPathSegment); if (is_null($node)) { $maxResultCount = $this->_providerWrapper->getConfiguration()->getMaxResultsPerCollection(); $node = new ExpandedProjectionNode($expandSubPathSegment, $resourceProperty, $resourceSetWrapper, $internalOrderByInfo, null, $pageSize == 0 ? null : $pageSize, $maxResultCount == PHP_INT_MAX ? null : $maxResultCount); $currentNode->addNode($node); } $currentNode = $node; } } }
/** * Create SegmentDescriptor for the first segment * * @param string $segmentIdentifier The identifier part of the first segment * @param string $keyPredicate The predicate part of the first segment if any else NULL * @param boolean $checkRights Whether to check the rights on this segment * * @return SegmentDescriptor Descriptor for the first segment * * @throws ODataException Exception if any validation fails */ private function _createFirstSegmentDescriptor($segmentIdentifier, $keyPredicate, $checkRights) { $descriptor = new SegmentDescriptor(); $descriptor->setIdentifier($segmentIdentifier); if ($segmentIdentifier === ODataConstants::URI_METADATA_SEGMENT) { $this->_assertion(is_null($keyPredicate)); $descriptor->setTargetKind(TargetKind::METADATA()); return $descriptor; } if ($segmentIdentifier === ODataConstants::URI_BATCH_SEGMENT) { $this->_assertion(is_null($keyPredicate)); $descriptor->setTargetKind(TargetKind::BATCH()); return $descriptor; } if ($segmentIdentifier === ODataConstants::URI_COUNT_SEGMENT) { throw ODataException::createBadRequestError(Messages::segmentParserSegmentNotAllowedOnRoot(ODataConstants::URI_COUNT_SEGMENT)); } if ($segmentIdentifier === ODataConstants::URI_LINK_SEGMENT) { throw ODataException::createBadRequestError(Messages::segmentParserSegmentNotAllowedOnRoot(ODataConstants::URI_LINK_SEGMENT)); } $resourceSetWrapper = $this->providerWrapper->resolveResourceSet($segmentIdentifier); if ($resourceSetWrapper === null) { throw ODataException::createResourceNotFoundError($segmentIdentifier); } $descriptor->setTargetResourceSetWrapper($resourceSetWrapper); $descriptor->setTargetResourceType($resourceSetWrapper->getResourceType()); $descriptor->setTargetSource(TargetSource::ENTITY_SET); $descriptor->setTargetKind(TargetKind::RESOURCE()); if ($keyPredicate !== null) { $keyDescriptor = $this->_createKeyDescriptor($segmentIdentifier . '(' . $keyPredicate . ')', $resourceSetWrapper->getResourceType(), $keyPredicate); $descriptor->setKeyDescriptor($keyDescriptor); if (!$keyDescriptor->isEmpty()) { $descriptor->setSingleResult(true); } } if ($checkRights) { $resourceSetWrapper->checkResourceSetRightsForRead($descriptor->isSingleResult()); } return $descriptor; }
/** * 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); } } } } }
/** * @param ProvidersWrapper $providers * @return IODataWriter */ public function writeServiceDocument(ProvidersWrapper $providers) { $writer = $this->xmlWriter; $writer->startElementNs(null, ODataConstants::ATOM_PUBLISHING_SERVICE_ELEMENT_NAME, ODataConstants::APP_NAMESPACE); $writer->writeAttributeNs(ODataConstants::XML_NAMESPACE_PREFIX, ODataConstants::XML_BASE_ATTRIBUTE_NAME, null, $this->baseUri); $writer->writeAttributeNs(ODataConstants::XMLNS_NAMESPACE_PREFIX, self::ATOM_NAMESPACE_PREFIX, null, ODataConstants::ATOM_NAMESPACE); $writer->writeAttributeNs(ODataConstants::XMLNS_NAMESPACE_PREFIX, self::APP_NAMESPACE_PREFIX, null, ODataConstants::APP_NAMESPACE); $writer->startElement(ODataConstants::ATOM_PUBLISHING_WORKSPACE_ELEMNT_NAME); $writer->startElementNs(self::ATOM_NAMESPACE_PREFIX, ODataConstants::ATOM_TITLE_ELELMET_NAME, null); $writer->text(ODataConstants::ATOM_PUBLISHING_WORKSPACE_DEFAULT_VALUE); $writer->endElement(); foreach ($providers->getResourceSets() as $resourceSetWrapper) { //start collection node $writer->startElement(ODataConstants::ATOM_PUBLISHING_COLLECTION_ELEMENT_NAME); $writer->writeAttribute(ODataConstants::ATOM_HREF_ATTRIBUTE_NAME, $resourceSetWrapper->getName()); //start title node $writer->startElementNs(self::ATOM_NAMESPACE_PREFIX, ODataConstants::ATOM_TITLE_ELELMET_NAME, null); $writer->text($resourceSetWrapper->getName()); //end title node $writer->endElement(); //end collection node $writer->endElement(); } //End workspace and service nodes $writer->endElement(); $writer->endElement(); return $this; }
/** * Test whether order by parser identify and remove path duplication */ public function testOrderByWithPathDuplication() { $northWindMetadata = NorthWindMetadata::Create(); $configuration = new ServiceConfiguration($northWindMetadata); $configuration->setEntitySetAccessRule('*', EntitySetRights::ALL); $providersWrapper = new ProvidersWrapper($northWindMetadata, $this->mockQueryProvider, $configuration, false); $resourceSetWrapper = $providersWrapper->resolveResourceSet('Order_Details'); $resourceType = $resourceSetWrapper->getResourceType(); $orderBy = 'Order/Price desc, Product/ProductName asc, Order/Price asc'; $internalOrderInfo = OrderByParser::parseOrderByClause($resourceSetWrapper, $resourceType, $orderBy, $providersWrapper); //The orderby path Order/Price appears twice, but parser will consider only first path $orderByInfo = $internalOrderInfo->getOrderByInfo(); //There are navigation (resource reference) properties in the orderby path so getNavigationPropertiesUsed should //not be null $naviUsed = $orderByInfo->getNavigationPropertiesUsed(); $this->assertFalse(is_null($naviUsed)); //3 path segment are there, but last one is duplicate of first one, so parser removes last one $this->assertEquals(count($naviUsed), 2); $this->assertTrue(is_array($naviUsed[0])); $this->assertTrue(is_array($naviUsed[1])); //one navgations used in first orderby 'Order' $this->assertEquals(count($naviUsed[0]), 1); //one navgations used in second orderby 'Prodcut' $this->assertEquals(count($naviUsed[1]), 1); $this->assertEquals($naviUsed[0][0]->getName(), 'Order'); $this->assertEquals($naviUsed[1][0]->getName(), 'Product'); $orderByPathSegments = $orderByInfo->getOrderByPathSegments(); $this->assertEquals(count($orderByPathSegments), 2); }
/** * Check wrapped resource set's resource type or any of the resource type derived * from the this resource type has bag property associated with it. * * @param ProvidersWrapper $provider Metadata query provider wrapper * * @return boolean */ public function hasBagProperty(ProvidersWrapper $provider) { $arrayToDetectLoop = array(); $hasBagProperty = $this->_resourceSet->getResourceType()->hasBagProperty($arrayToDetectLoop); unset($arrayToDetectLoop); // This will check only the resource type associated with // the resource set, we need to check presence of bag property // in resource type which is derived form this resource type also. if (!$hasBagProperty) { $derivedTypes = $provider->getDerivedTypes($this->_resourceSet->getResourceType()); foreach ($derivedTypes as $derivedType) { $arrayToDetectLoop = array(); if ($derivedType->hasBagProperty($arrayToDetectLoop)) { return true; } } } return false; }
/** * One can expand a navigation property only if corresponding resource set is visible * */ public function testExpandWithNonVisibleResourceSet() { $northWindMetadata = NorthWindMetadata::Create(); $queryProvider = new NorthWindQueryProvider(); $configuration = new ServiceConfiguration($northWindMetadata); //Make 'Customers' and 'Orders' visible, make 'Order_Details' invisible $configuration->setEntitySetAccessRule('Customers', EntitySetRights::ALL); $configuration->setEntitySetAccessRule('Orders', EntitySetRights::ALL); $providersWrapper = new ProvidersWrapper($northWindMetadata, $queryProvider, $configuration, false); $customersResourceSetWrapper = $providersWrapper->resolveResourceSet('Customers'); $customerResourceType = $customersResourceSetWrapper->getResourceType(); $exceptionThrown = false; try { $projectionTree = ExpandProjectionParser::parseExpandAndSelectClause($customersResourceSetWrapper, $customerResourceType, null, null, null, 'Orders/Order_Details', null, $providersWrapper); $this->fail('An expected ODataException for navigation to invisible resource set has not been thrown'); } catch (ODataException $odataException) { $this->assertStringEndsWith("(Check the resource set of the navigation property 'Order_Details' is visible)", $odataException->getMessage()); } }
public function testGetOutputTwoResourceSets() { $fakeResourceSet1 = Phockito::mock('POData\\Providers\\Metadata\\ResourceSetWrapper'); Phockito::when($fakeResourceSet1->getName())->return("Name 1"); $fakeResourceSet2 = Phockito::mock('POData\\Providers\\Metadata\\ResourceSetWrapper'); //TODO: this certainly doesn't seem right...see #73 Phockito::when($fakeResourceSet2->getName())->return("XML escaped stuff \" ' <> & ?"); $fakeResourceSets = array($fakeResourceSet1, $fakeResourceSet2); Phockito::when($this->mockProvider->getResourceSets())->return($fakeResourceSets); $fakeBaseURL = "http://some/place/some/where/" . uniqid(); $writer = new AtomODataWriter($fakeBaseURL); $actual = $writer->writeServiceDocument($this->mockProvider)->getOutput(); $expected = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <service xml:base="' . $fakeBaseURL . '" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app"> <workspace> <atom:title>Default</atom:title> <collection href="Name 1"> <atom:title>Name 1</atom:title> </collection> <collection href="XML escaped stuff " \' <> & ?"> <atom:title>XML escaped stuff " \' <> & ?</atom:title> </collection> </workspace> </service> '; $this->assertEquals($expected, $actual); }
/** * test the creation of nextlink from an object. * Test building of link with guid sub-value */ public function testCreationOfNextLink4() { $northWindMetadata = NorthWindMetadata::Create(); $configuration = new ServiceConfiguration($northWindMetadata); $configuration->setEntitySetAccessRule('*', EntitySetRights::ALL); $providersWrapper = new ProvidersWrapper($northWindMetadata, $this->mockQueryProvider, $configuration, false); $resourceSetWrapper = $providersWrapper->resolveResourceSet('Customers'); $resourceType = $resourceSetWrapper->getResourceType(); $orderBy = 'CustomerID, CustomerGuid'; $internalOrderByInfo = OrderByParser::parseOrderByClause($resourceSetWrapper, $resourceType, $orderBy, $providersWrapper); $skipToken = "null, guid'05b242e752eb46bd8f0e6568b72cd9a5'"; $internalSkipTokenInfo = SkipTokenParser::parseSkipTokenClause($resourceType, $internalOrderByInfo, $skipToken); $keyObject = $internalSkipTokenInfo->getKeyObject(); $lastObject = new Customer2(); $lastObject->CustomerID = 'ABC'; $lastObject->CustomerGuid = '{05b242e7-52eb-46bd-8f0e-6568b72cd9a5}'; $nextLink = $internalSkipTokenInfo->buildNextPageLink($lastObject); $this->assertEquals($nextLink, "'ABC', guid'%7B05b242e7-52eb-46bd-8f0e-6568b72cd9a5%7D'"); }
/** * Build 'OrderBy Tree' from the given orderby path segments, also build * comparsion function for each path segment. * * @param array(array) &$orderByPathSegments Collection of orderby path segments, * this is passed by reference * since we need this function to * modify this array in two cases: * 1. if asc or desc present, then the * corresponding sub path segment * should be removed * 2. remove duplicate orderby path * segment * * @return void * * @throws ODataException If any error occurs while processing the orderby path * segments */ private function _buildOrderByTree(&$orderByPathSegments) { foreach ($orderByPathSegments as $index1 => &$orderBySubPathSegments) { $currentNode = $this->_rootOrderByNode; $currentObject = $this->_dummyObject; $ascending = true; $subPathCount = count($orderBySubPathSegments); // Check sort order is specified in the path, if so set a // flag and remove that segment if ($subPathCount > 1) { if ($orderBySubPathSegments[$subPathCount - 1] === '*desc') { $ascending = false; unset($orderBySubPathSegments[$subPathCount - 1]); $subPathCount--; } else { if ($orderBySubPathSegments[$subPathCount - 1] === '*asc') { unset($orderBySubPathSegments[$subPathCount - 1]); $subPathCount--; } } } $ancestors = array($this->_rootOrderByNode->getResourceSetWrapper()->getName()); foreach ($orderBySubPathSegments as $index2 => $orderBySubPathSegment) { $isLastSegment = $index2 == $subPathCount - 1; $resourceSetWrapper = null; $resourceType = $currentNode->getResourceType(); $resourceProperty = $resourceType->resolveProperty($orderBySubPathSegment); if (is_null($resourceProperty)) { throw ODataException::createSyntaxError(Messages::orderByParserPropertyNotFound($resourceType->getFullName(), $orderBySubPathSegment)); } if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG)) { throw ODataException::createBadRequestError(Messages::orderByParserBagPropertyNotAllowed($resourceProperty->getName())); } else { if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) { if (!$isLastSegment) { throw ODataException::createBadRequestError(Messages::orderByParserPrimitiveAsIntermediateSegment($resourceProperty->getName())); } $type = $resourceProperty->getInstanceType(); if ($type instanceof Binary) { throw ODataException::createBadRequestError(Messages::orderByParserSortByBinaryPropertyNotAllowed($resourceProperty->getName())); } } else { if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE || $resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE) { $this->_assertion($currentNode instanceof OrderByRootNode || $currentNode instanceof OrderByNode); $resourceSetWrapper = $currentNode->getResourceSetWrapper(); $this->_assertion(!is_null($resourceSetWrapper)); $resourceSetWrapper = $this->_providerWrapper->getResourceSetWrapperForNavigationProperty($resourceSetWrapper, $resourceType, $resourceProperty); if (is_null($resourceSetWrapper)) { throw ODataException::createBadRequestError(Messages::badRequestInvalidPropertyNameSpecified($resourceType->getFullName(), $orderBySubPathSegment)); } if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE) { throw ODataException::createBadRequestError(Messages::orderByParserResourceSetReferenceNotAllowed($resourceProperty->getName(), $resourceType->getFullName())); } $resourceSetWrapper->checkResourceSetRightsForRead(true); if ($isLastSegment) { throw ODataException::createBadRequestError(Messages::orderByParserSortByNavigationPropertyIsNotAllowed($resourceProperty->getName())); } $ancestors[] = $orderBySubPathSegment; } else { if ($resourceProperty->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) { if ($isLastSegment) { throw ODataException::createBadRequestError(Messages::orderByParserSortByComplexPropertyIsNotAllowed($resourceProperty->getName())); } $ancestors[] = $orderBySubPathSegment; } else { throw ODataException::createInternalServerError(Messages::orderByParserUnexpectedPropertyType()); } } } } $node = $currentNode->findNode($orderBySubPathSegment); if (is_null($node)) { if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) { $node = new OrderByLeafNode($orderBySubPathSegment, $resourceProperty, $ascending); $this->_comparisonFunctions[] = $node->buildComparisonFunction($ancestors); } else { if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCE_REFERENCE) { $node = new OrderByNode($orderBySubPathSegment, $resourceProperty, $resourceSetWrapper); // Initialize this member variable (identified by // $resourceProperty) of parent object. try { $dummyProperty = new \ReflectionProperty($currentObject, $resourceProperty->getName()); $object = $resourceProperty->getInstanceType()->newInstance(); $dummyProperty->setValue($currentObject, $object); $currentObject = $object; } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::orderByParserFailedToAccessOrInitializeProperty($resourceProperty->getName(), $resourceType->getName())); } } else { if ($resourceProperty->getKind() == ResourcePropertyKind::COMPLEX_TYPE) { $node = new OrderByNode($orderBySubPathSegment, $resourceProperty, null); // Initialize this member variable // (identified by $resourceProperty)of parent object. try { $dummyProperty = new \ReflectionProperty($currentObject, $resourceProperty->getName()); $object = $resourceProperty->getInstanceType()->newInstance(); $dummyProperty->setValue($currentObject, $object); $currentObject = $object; } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::orderByParserFailedToAccessOrInitializeProperty($resourceProperty->getName(), $resourceType->getName())); } } } } $currentNode->addNode($node); } else { try { $reflectionClass = new \ReflectionClass(get_class($currentObject)); $reflectionProperty = $reflectionClass->getProperty($resourceProperty->getName()); $reflectionProperty->setAccessible(true); $currentObject = $reflectionProperty->getValue($currentObject); //$dummyProperty = new \ReflectionProperty( // $currentObject, $resourceProperty->getName() //); //$currentObject = $dummyProperty->getValue($currentObject); } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::orderByParserFailedToAccessOrInitializeProperty($resourceProperty->getName(), $resourceType->getName())); } if ($node instanceof OrderByLeafNode) { //remove duplicate orderby path unset($orderByPathSegments[$index1]); } } $currentNode = $node; } } }
/** * Gets resource sets which are visible * * @return ResourceSetWrapper[] */ public function getResourceSets() { return $this->providersWrapper->getResourceSets(); }
/** * @param ProvidersWrapper $providers * @return IODataWriter */ public function writeServiceDocument(ProvidersWrapper $providers) { $writer = $this->_writer; $writer->startObjectScope()->writeName("d")->startObjectScope()->writeName(ODataConstants::ENTITY_SET)->startArrayScope(); foreach ($providers->getResourceSets() as $resourceSetWrapper) { $writer->writeValue($resourceSetWrapper->getName()); } $writer->endScope()->endScope()->endScope(); return $this; }
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()); }
public function testGetOutputTwoResourceSets() { $fakeResourceSet1 = Phockito::mock('POData\\Providers\\Metadata\\ResourceSetWrapper'); Phockito::when($fakeResourceSet1->getName())->return("Name 1"); $fakeResourceSet2 = Phockito::mock('POData\\Providers\\Metadata\\ResourceSetWrapper'); //TODO: this certainly doesn't seem right...see #73 Phockito::when($fakeResourceSet2->getName())->return("XML escaped stuff \" ' <> & ?"); $fakeResourceSets = array($fakeResourceSet1, $fakeResourceSet2); Phockito::when($this->mockProvider->getResourceSets())->return($fakeResourceSets); $writer = new JsonLightODataWriter(JsonLightMetadataLevel::FULL(), $this->serviceBase); $actual = $writer->writeServiceDocument($this->mockProvider)->getOutput(); $expected = '{ "d":{ "EntitySet":[ "Name 1","XML escaped stuff \\" \' <> & ?" ] } }'; $this->assertEquals($expected, $actual); }
/** * If last sub path segment specified in the select clause does not appear in the prjection tree, * then parser will create 'ProjectionNode' for them */ public function testProjectionNodeCreation() { $northWindMetadata = NorthWindMetadata::Create(); $queryProvider = new NorthWindQueryProvider(); $configuration = new ServiceConfiguration($northWindMetadata); $configuration->setEntitySetAccessRule('*', EntitySetRights::ALL); $providersWrapper = new ProvidersWrapper($northWindMetadata, $queryProvider, $configuration, false); $ordersResourceSetWrapper = $providersWrapper->resolveResourceSet('Orders'); $orderResourceType = $ordersResourceSetWrapper->getResourceType(); //test selection of properties which is not included in expand clause //1 primitve ('Order_Details/UnitPrice') and 1 link to navigation 'Customer' $projectionTreeRoot = ExpandProjectionParser::parseExpandAndSelectClause($ordersResourceSetWrapper, $orderResourceType, null, null, null, 'Order_Details', 'Order_Details/UnitPrice, Customer', $providersWrapper); //expand option is absent $this->assertTrue($projectionTreeRoot->isExpansionSpecified()); //select is applied $this->assertTrue($projectionTreeRoot->isSelectionSpecified()); $this->assertFalse($projectionTreeRoot->canSelectAllImmediateProperties()); $this->assertFalse($projectionTreeRoot->canSelectAllProperties()); //there are 2 child nodes for the root $this->assertEquals(count($projectionTreeRoot->getChildNodes()), 2); //The child nodes one 'ProjectionNode' Customer and one 'ExpandedProjectionNode' for 'Order' $childNodes = $projectionTreeRoot->getChildNodes(); $this->assertTrue(array_key_exists('Order_Details', $childNodes)); $this->assertTrue(array_key_exists('Customer', $childNodes)); $this->assertTrue($childNodes['Order_Details'] instanceof ExpandedProjectionNode); $this->assertTrue($childNodes['Customer'] instanceof ProjectionNode); //'Order_Detials' has a child node $childNodes = $childNodes['Order_Details']->getChildNodes(); $this->assertEquals(count($childNodes), 1); $this->assertTrue(array_key_exists('UnitPrice', $childNodes)); $this->assertTrue($childNodes['UnitPrice'] instanceof ProjectionNode); }