/** * 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()); } }
/** * Process the $expand and $select option and update the request description. * * @return void * * @throws ODataException Throws bad request error in the following cases * (1) If $expand or select cannot be applied to the * requested resource. * (2) If projection is disabled by the developer * (3) If some error occurs while parsing the options */ private function _processExpandAndSelect() { $expand = $this->service->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_EXPAND); if (!is_null($expand)) { $this->_checkExpandOrSelectApplicable(ODataConstants::HTTPQUERY_STRING_EXPAND); } $select = $this->service->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SELECT); if (!is_null($select)) { if (!$this->service->getConfiguration()->getAcceptProjectionRequests()) { throw ODataException::createBadRequestError(Messages::configurationProjectionsNotAccepted()); } $this->_checkExpandOrSelectApplicable(ODataConstants::HTTPQUERY_STRING_SELECT); } // We will generate RootProjectionNode in case of $link request also, but // expand and select in this case must be null (we are ensuring this above) // 'RootProjectionNode' is required while generating next page Link if ($this->_expandSelectApplicable || $this->request->isLinkUri()) { $rootProjectionNode = ExpandProjectionParser::parseExpandAndSelectClause($this->request->getTargetResourceSetWrapper(), $this->request->getTargetResourceType(), $this->request->getInternalOrderByInfo(), $this->request->getSkipCount(), $this->request->getTopCount(), $expand, $select, $this->service->getProvidersWrapper()); if ($rootProjectionNode->isSelectionSpecified()) { $this->request->raiseMinVersionRequirement(2, 0); } if ($rootProjectionNode->hasPagedExpandedResult()) { $this->request->raiseResponseVersion(2, 0); } $this->request->setRootProjectionNode($rootProjectionNode); } }
/** * 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); }