/** * Build 'OrderBy Tree' from the given orderby path segments, also build * comparsion function for each path segment. * * @param array(array) &$ordeyByPathSegments 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 * corrosponding 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(&$ordeyByPathSegments) { foreach ($ordeyByPathSegments as $index1 => &$ordeyBySubPathSegments) { $currentNode = $this->_rootOrderByNode; $currentObject = $this->_dummyObject; $ascending = true; $subPathCount = count($ordeyBySubPathSegments); // Check sort order is specified in the path, if so set a // flag and remove that segment if ($subPathCount > 1) { if ($ordeyBySubPathSegments[$subPathCount - 1] === '*desc') { $ascending = false; unset($ordeyBySubPathSegments[$subPathCount - 1]); $subPathCount--; } else { if ($ordeyBySubPathSegments[$subPathCount - 1] === '*asc') { unset($ordeyBySubPathSegments[$subPathCount - 1]); $subPathCount--; } } } $ancestors = array($this->_rootOrderByNode->getResourceSetWrapper()->getName()); foreach ($ordeyBySubPathSegments as $index2 => $orderBySubPathSegment) { $isLastSegment = $index2 == $subPathCount - 1; $resourceSetWrapper = null; $resourceType = $currentNode->getResourceType(); $resourceProperty = $resourceType->tryResolvePropertyTypeByName($orderBySubPathSegment); if (is_null($resourceProperty)) { ODataException::createSyntaxError(Messages::orderByParserPropertyNotFound($resourceType->getFullName(), $orderBySubPathSegment)); } if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG)) { ODataException::createBadRequestError(Messages::orderByParserBagPropertyNotAllowed($resourceProperty->getName())); } else { if ($resourceProperty->isKindOf(ResourcePropertyKind::PRIMITIVE)) { if (!$isLastSegment) { ODataException::createBadRequestError(Messages::orderByParserPrimitiveAsIntermediateSegment($resourceProperty->getName())); } $type = $resourceProperty->getInstanceType(); if ($type instanceof Binary) { 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)) { ODataException::createBadRequestError(Messages::badRequestInvalidPropertyNameSpecified($resourceType->getFullName(), $orderBySubPathSegment)); } if ($resourceProperty->getKind() == ResourcePropertyKind::RESOURCESET_REFERENCE) { ODataException::createBadRequestError(Messages::orderbyParserResourceSetReferenceNotAllowed($resourceProperty->getName(), $resourceType->getFullName())); } $resourceSetWrapper->checkResourceSetRightsForRead(true); if ($isLastSegment) { ODataException::createBadRequestError(Messages::orderByParserSortByNavigationPropertyIsNotAllowed($resourceProperty->getName())); } $ancestors[] = $orderBySubPathSegment; } else { if ($resourceProperty->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) { if ($isLastSegment) { ODataException::createBadRequestError(Messages::orderByParserSortByComplexPropertyIsNotAllowed($resourceProperty->getName())); } $ancestors[] = $orderBySubPathSegment; } else { 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 { $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($ordeyByPathSegments[$index1]); } } $currentNode = $node; } } }