/** * Creates new instance of ResourceSet * * @param string $name Name of the resource set (entity set) * @param ResourceType $resourceType ResourceType describing the resource * this entity set holds * * @throws \InvalidArgumentException */ public function __construct($name, ResourceType $resourceType) { if ($resourceType->getResourceTypeKind() != ResourceTypeKind::ENTITY) { throw new \InvalidArgumentException(Messages::resourceSetContainerMustBeAssociatedWithEntityType()); } $this->_name = $name; $this->_resourceType = $resourceType; }
/** * 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; }
/** * To check this relationship belongs to a specfic entity property * * @param ResourceType $resourceType The type of the entity * @param ResourceProperty|null $resourceProperty The property in the entity * * @return boolean */ public function isBelongsTo(ResourceType $resourceType, $resourceProperty) { $flag1 = is_null($resourceProperty); $flag2 = is_null($this->_resourceProperty); if ($flag1 != $flag2) { return false; } if ($flag1 === true) { return strcmp($resourceType->getFullName(), $this->_resourceType->getFullName()) == 0; } return strcmp($resourceType->getFullName(), $this->_resourceType->getFullName()) == 0 && strcmp($resourceProperty->getName(), $this->_resourceProperty->getName()) == 0; }
/** * Call-back for property access expression * * @param PropertyAccessExpression $expression The property access expression * * @return string */ public function onPropertyAccessExpression($expression) { $parent = $expression; $variable = null; $entityTypeName = $this->resourceType->getName(); $propertyName = $parent->getResourceProperty()->getName(); if (is_array($this->entityMapping)) { if (array_key_exists($entityTypeName, $this->entityMapping)) { if (array_key_exists($propertyName, $this->entityMapping[$entityTypeName])) { return $this->entityMapping[$entityTypeName][$propertyName]; } } } return $propertyName; }
public function testGetResourceAssociationSetEndIsNotVisible() { $fakePropName = "Fake Prop"; Phockito::when($this->mockResourceProperty->getName())->return($fakePropName); Phockito::when($this->mockResourceType->resolvePropertyDeclaredOnThisType($fakePropName))->return($this->mockResourceProperty); $fakeTypeName = "Fake Type"; Phockito::when($this->mockResourceType->getName())->return($fakeTypeName); $fakeSetName = "Fake Set"; Phockito::when($this->mockResourceSet->getName())->return($fakeSetName); Phockito::when($this->mockResourceSet->getResourceType())->return($this->mockResourceType); Phockito::when($this->mockResourceSet2->getResourceType())->return($this->mockResourceType2); //Indicate the resource set is visible Phockito::when($this->mockServiceConfig->getEntitySetAccessRule($this->mockResourceSet))->return(EntitySetRights::READ_SINGLE); //Indicate the resource set is visible Phockito::when($this->mockServiceConfig->getEntitySetAccessRule($this->mockResourceSet2))->return(EntitySetRights::NONE); Phockito::when($this->mockMetadataProvider->getResourceAssociationSet($this->mockResourceSet, $this->mockResourceType, $this->mockResourceProperty))->return($this->mockResourceAssociationSet); Phockito::when($this->mockResourceAssociationSet->getResourceAssociationSetEnd($this->mockResourceSet, $this->mockResourceType, $this->mockResourceProperty))->return($this->mockResourceAssociationSetEnd); Phockito::when($this->mockResourceAssociationSet->getRelatedResourceAssociationSetEnd($this->mockResourceSet, $this->mockResourceType, $this->mockResourceProperty))->return($this->mockResourceAssociationSetEnd); Phockito::when($this->mockResourceAssociationSetEnd->getResourceSet())->return($this->mockResourceSet2); Phockito::when($this->mockResourceAssociationSetEnd->getResourceType())->return($this->mockResourceType2); $wrapper = $this->getMockedWrapper(); $actual = $wrapper->getResourceAssociationSet($this->mockResourceSet, $this->mockResourceType, $this->mockResourceProperty); $this->assertNull($actual); }
/** * Convert the given primitive value to string. * Note: This method will not handle null primitive value. * * @param ResourceType &$primtiveResourceType Type of the primitive property * whose value need to be converted. * @param mixed $primitiveValue Primitive value to convert. * @param string &$stringValue On return, this parameter will * contain converted value. * * @return void */ private function _primitiveToString(ResourceType &$primtiveResourceType, $primitiveValue, &$stringValue) { $type = $primtiveResourceType->getInstanceType(); if ($type instanceof Boolean) { $stringValue = $primitiveValue === true ? 'true' : 'false'; } else { if ($type instanceof Binary) { $stringValue = base64_encode($primitiveValue); } else { if ($type instanceof DateTime && $primitiveValue instanceof \DateTime) { $stringValue = $primitiveValue->format(\DateTime::ATOM); } else { if ($type instanceof String) { $stringValue = utf8_encode($primitiveValue); } else { $stringValue = strval($primitiveValue); } } } } }
/** * To add a navigation property (resource set or resource reference) * to a resource type * * @param ResourceType $resourceType The resource type to add * the resource reference * or resource * reference set property to * @param string $name The name of the * property to add * @param ResourceSet $targetResourceSet The resource set the * resource reference * or reference * set property * ponits to * @param ResourcePropertyKind $resourcePropertyKind The property kind * * @return void */ private function _addReferencePropertyInternal(ResourceType $resourceType, $name, ResourceSet $targetResourceSet, $resourcePropertyKind) { try { $resourceType->getInstanceType()->getProperty($name); } catch (\ReflectionException $exception) { throw new InvalidOperationException('Can\'t add a property which does not exist on the instance type.'); } if (!($resourcePropertyKind == ResourcePropertyKind::RESOURCESET_REFERENCE || $resourcePropertyKind == ResourcePropertyKind::RESOURCE_REFERENCE)) { throw new InvalidOperationException('Property kind should be ResourceSetReference or ResourceReference'); } $targetResourceType = $targetResourceSet->getResourceType(); $resourceProperty = new ResourceProperty($name, null, $resourcePropertyKind, $targetResourceType); $resourceType->addProperty($resourceProperty); //Create instance of AssociationSet for this relationship $sourceResourceSet = $resourceType->getCustomState(); if (is_null($sourceResourceSet)) { throw new InvalidOperationException('Failed to retrieve the custom state from ' . $resourceType->getName()); } //Customer_Orders_Orders, Order_Customer_Customers //(source type::name _ source property::name _ target set::name) $setKey = $resourceType->getName() . '_' . $name . '_' . $targetResourceSet->getName(); $set = new ResourceAssociationSet($setKey, new ResourceAssociationSetEnd($sourceResourceSet, $resourceType, $resourceProperty), new ResourceAssociationSetEnd($targetResourceSet, $targetResourceSet->getResourceType(), null)); $this->associationSets[$setKey] = $set; }
private function _getOrderResourceType() { $orderResType = new ResourceType(new \ReflectionClass('UnitTests\\POData\\Facets\\NorthWind1\\Order2'), ResourceTypeKind::ENTITY, 'Order', 'Northwind'); $intResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::INT32); $orderIDPrimProperty = new ResourceProperty('OrderID', null, ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY, $intResourceType); $dateTimeResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::DATETIME); $orderDatePrimProperty = new ResourceProperty('OrderDate', null, ResourcePropertyKind::PRIMITIVE, $dateTimeResourceType); $stringResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::STRING); $orderShipNamePrimProperty = new ResourceProperty('ShipName', null, ResourcePropertyKind::PRIMITIVE, $stringResourceType); $orderResType->addProperty($orderIDPrimProperty); $orderResType->addProperty($orderDatePrimProperty); $orderResType->addProperty($orderShipNamePrimProperty); return $orderResType; }
/** * Check this resource type instance has bag property associated with it * Note: This is an internal method used by library. Devs don't use this. * * @param array &$arrayToDetectLoopInComplexType array for detecting loop. * * @return boolean true if resource type instance has bag property else false */ public function hasBagProperty(&$arrayToDetectLoopInComplexType) { // Note: Calling this method will initialize _bagProperties // and _hasBagProperty flag to a boolean value // from null depending on the current state of // _propertiesDeclaredOnThisType array, so method // should be called only after adding all properties if (!is_null($this->_hasBagProperty)) { return $this->_hasBagProperty; } if ($this->_baseType != null && $this->_baseType->hasBagProperty($arrayToDetectLoopInComplexType)) { $this->_hasBagProperty = true; } else { foreach ($this->_propertiesDeclaredOnThisType as $resourceProperty) { $hasBagInComplex = false; if ($resourceProperty->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) { //We can say current ResouceType ("this") //is contains a bag property if: //1. It contain a property of kind bag. //2. It contains a normal complex property //with a sub property of kind bag. //The second case can be further expanded, i.e. //if the normal complex property //has a normal complex sub property with a //sub property of kind bag. //So for complex type we recursively call this //function to check for bag. //Shown below how looping can happen in complex type: //Customer ResourceType (id1) //{ // .... // Address: Address ResourceType (id2) // { // ..... // AltAddress: Address ResourceType (id2) // { // ... // } // } //} // //Here the resource type of Customer::Address and //Customer::Address::AltAddress //are same, this is a loop, we need to detect //this and avoid infinite recursive loop. // $count = count($arrayToDetectLoopInComplexType); $foundLoop = false; for ($i = 0; $i < $count; $i++) { if ($arrayToDetectLoopInComplexType[$i] === $resourceProperty->getResourceType()) { $foundLoop = true; break; } } if (!$foundLoop) { $arrayToDetectLoopInComplexType[$count] = $resourceProperty->getResourceType(); $hasBagInComplex = $resourceProperty->getResourceType()->hasBagProperty($arrayToDetectLoopInComplexType); unset($arrayToDetectLoopInComplexType[$count]); } } if ($resourceProperty->isKindOf(ResourcePropertyKind::BAG) || $hasBagInComplex) { $this->_hasBagProperty = true; break; } } } return $this->_hasBagProperty; }
/** * Returns the etag for the given resource. * Note: This function will not add W\" prefix and " suffix, its callers * repsonsability. * * @param mixed &$entryObject Resource for which etag value needs to * be returned * @param ResourceType &$resourceType Resource type of the $entryObject * * @return string|null ETag value for the given resource (with values encoded * for use in a URI) there are etag properties, NULL if * there is no etag property. */ protected function getETagForEntry(&$entryObject, ResourceType &$resourceType) { $eTag = null; $comma = null; foreach ($resourceType->getETagProperties() as $eTagProperty) { $type = $eTagProperty->getInstanceType(); self::assert(!is_null($type) && $type instanceof IType, '!is_null($type) && $type instanceof IType'); $value = null; try { //TODO #88...also this seems like dupe work $reflectionProperty = new \ReflectionProperty($entryObject, $eTagProperty->getName()); $value = $reflectionProperty->getValue($entryObject); } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::failedToAccessProperty($eTagProperty->getName(), $resourceType->getName())); } if (is_null($value)) { $eTag = $eTag . $comma . 'null'; } else { $eTag = $eTag . $comma . $type->convertToOData($value); } $comma = ','; } if (!is_null($eTag)) { // If eTag is made up of datetime or string properties then the above // IType::convertToOData will perform utf8 and url encode. But we don't // want this for eTag value. $eTag = urldecode(utf8_decode($eTag)); return rtrim($eTag, ','); } return null; }
/** * Returns the etag for the given resource. * * @param mixed $entryObject Resource for which etag value * needs to be returned * @param ResourceType $resourceType Resource type of the $entryObject * * @return string|null ETag value for the given resource * (with values encoded for use in a URI) * if there are etag properties, NULL if there is no etag property. */ protected function getETagForEntry($entryObject, ResourceType $resourceType) { $eTag = null; $comma = null; foreach ($resourceType->getETagProperties() as $eTagProperty) { $type = $eTagProperty->getInstanceType(); $this->assert(!is_null($type) && $type instanceof IType, '!is_null($type) && $type instanceof IType'); $value = $this->getPropertyValue($entryObject, $resourceType, $eTagProperty); if (is_null($value)) { $eTag = $eTag . $comma . 'null'; } else { $eTag = $eTag . $comma . $type->convertToOData($value); } $comma = ','; } if (!is_null($eTag)) { // If eTag is made up of datetime or string properties then the above // IType::converToOData will perform utf8 and url encode. But we don't // want this for eTag value. $eTag = urldecode(utf8_decode($eTag)); return ODataConstants::HTTP_WEAK_ETAG_PREFIX . rtrim($eTag, ',') . '"'; } return null; }
/** * Get the instance type. If the property is of kind 'Complex', * 'ResourceReference' or 'ResourceSetReference' then this function returns * refernece to ReflectionClass instance for the type. If the property of * kind 'Primitive' then this function returns ITYpe instance for the type. * * @return \ReflectionClass|IType */ public function getInstanceType() { return $this->_propertyResourceType->getInstanceType(); }
/** * Validates the given instance of ResourceType * * @param ResourceType $resourceType The ResourceType to validate * * @return ResourceType * * @throws ODataException Exception if $resourceType is invalid */ private function _validateResourceType(ResourceType $resourceType) { $cacheKey = $resourceType->getName(); if (array_key_exists($cacheKey, $this->typeCache)) { return $this->typeCache[$cacheKey]; } //TODO: Do validation if any for the ResourceType $this->typeCache[$cacheKey] = $resourceType; return $resourceType; }
/** * This function perform the following tasks with the help of internal helper * functions * (1) Read the orderby clause and perform basic syntax errors * (2) Build 'Order By Tree', creates anonymous sorter function for each leaf * node and check for error * (3) Build 'OrderInfo' structure, holds information about the navigation * properties used in the orderby clause (if any) and orderby path if * IDSQP implementor want to perform sorting * (4) Build top level anonymous sorter function * (4) Release resources hold by the 'Order By Tree' * (5) Create 'InternalOrderInfo' structure, which wraps 'OrderInfo' and top * level sorter function * * @param ResourceSetWrapper $resourceSetWrapper ResourceSetWrapper for the resource targeted by resource path. * @param ResourceType $resourceType ResourceType for the resource targeted by resource path. * @param string $orderBy The orderby clause. * @param ProvidersWrapper $providerWrapper Reference to the wrapper for IDSQP and IDSMP impl. * * @return InternalOrderByInfo * * @throws ODataException If any error occur while parsing orderby clause */ public static function parseOrderByClause(ResourceSetWrapper $resourceSetWrapper, ResourceType $resourceType, $orderBy, ProvidersWrapper $providerWrapper) { $orderByParser = new OrderByParser($providerWrapper); try { $orderByParser->_dummyObject = $resourceType->getInstanceType()->newInstance(); } catch (\ReflectionException $reflectionException) { throw ODataException::createInternalServerError(Messages::orderByParserFailedToCreateDummyObject()); } $orderByParser->_rootOrderByNode = new OrderByRootNode($resourceSetWrapper, $resourceType); $orderByPathSegments = $orderByParser->_readOrderBy($orderBy); $orderByParser->_buildOrderByTree($orderByPathSegments); $orderByParser->_createOrderInfo($orderByPathSegments); $orderByParser->_generateTopLevelComparisonFunction(); //Recursively release the resources $orderByParser->_rootOrderByNode->free(); //creates internal order info wrapper $internalOrderInfo = new InternalOrderByInfo($orderByParser->_orderByInfo, $orderByParser->_comparisonFunctions, $orderByParser->_topLevelComparisonFunction, $orderByParser->_dummyObject); unset($orderByParser->_orderByInfo); unset($orderByParser->_topLevelComparisonFunction); return $internalOrderInfo; }
/** * Gets full name of this type in EDM namespace * Note: implementation of IType::getFullTypeName * * @return string */ public function getFullTypeName() { return $this->_resourceType->getFullName(); }
/** * Write all named streams in the given entity type * * @param ResourceType $resourceType resource type * * @return void */ private function _writeNamedStreams(ResourceType $resourceType) { $namedStreams = $resourceType->getNamedStreamsDeclaredOnThisType(); if (!empty($namedStreams)) { $this->_xmlWriter->startElementNs(null, ODataConstants::DATAWEB_NAMEDSTREAMS_ELEMENT, ODataConstants::ODATA_METADATA_NAMESPACE); foreach ($namedStreams as $namedStreamName => $resourceStreamInfo) { $this->_xmlWriter->startElementNs(null, ODataConstants::DATAWEB_NAMEDSTREAM_ELEMENT, ODataConstants::ODATA_METADATA_NAMESPACE); $this->_xmlWriter->writeAttribute(ODataConstants::NAME, $resourceStreamInfo->getName()); $this->_xmlWriter->endElement(); } $this->_xmlWriter->endElement(); } }
/** * Gets and validate the ResourceAssociationSet instance for the * given source resource association end * This function first searches the ResourceAssociationSet cache, * if found return it otherwise * get the association set from metadata wrapper, * validate, cache and return it. * * @param ResourceSetWrapper $resourceSet Resource set of the * source association end * @param ResourceType $resourceType Resource type of the * source association end * @param ResourceProperty $navigationProperty Resource property of the * source association end * * @return ResourceAssociationSet|null The association set instance for the * given association set end, * NULL if the metadata wrapper * returns NULL * (either IDSMP implementation * returns null or * target resource set is invisible) * * @throws InvalidOperationException If validation of AssociationSet fails * @throws ODataException If validation fails at * ProvidersWrapper::getResourceAssociationSet */ private function _getResourceAssociationSet(ResourceSetWrapper $resourceSet, ResourceType $resourceType, ResourceProperty $navigationProperty) { $associationSetLookupKey = $resourceSet->getName() . '_' . $resourceType->getFullName() . '_' . $navigationProperty->getName(); if (array_key_exists($associationSetLookupKey, $this->_resourceAssociationSets)) { return $this->_resourceAssociationSets[$associationSetLookupKey]; } $resourceAssociationSet = $this->providersWrapper->getResourceAssociationSet($resourceSet, $resourceType, $navigationProperty); if (is_null($resourceAssociationSet)) { //Either the related ResourceSet is invisible or IDSMP implementation returns null return null; } /** * @var ResourceAssociationSetEnd */ $relatedEnd = $resourceAssociationSet->getRelatedResourceAssociationSetEnd($resourceSet->getResourceSet(), $resourceType, $navigationProperty); //For bidirectional relationship IDSMP::getResourceAssociationSet should //return same association set when called from either end if (!is_null($relatedEnd->getResourceProperty())) { //No need to check whether the following call returns NULL, //because the above call //providersWrapper::getResourceAssociationSet //causes the metadata wrapper to check the visibility of //related resource set and cache the corresponding wrapper. //If found invisible it would have return NULL, //which we are any way handling above. $relatedResourceSetWrapper = $this->providersWrapper->validateResourceSetAndGetWrapper($relatedEnd->getResourceSet()); $reverseResourceAssociationSet = $this->providersWrapper->getResourceAssociationSet($relatedResourceSetWrapper, $relatedEnd->getResourceType(), $relatedEnd->getResourceProperty()); if (is_null($reverseResourceAssociationSet) || !is_null($reverseResourceAssociationSet) && $resourceAssociationSet->getName() != $reverseResourceAssociationSet->getName()) { throw new InvalidOperationException(Messages::metadataAssociationTypeSetBidirectionalAssociationMustReturnSameResourceAssociationSetFromBothEnd()); } } $reverseAssociationSetLookupKey = null; if (!is_null($relatedEnd->getResourceProperty())) { $reverseAssociationSetLookupKey = $relatedEnd->getResourceSet()->getName() . '_' . $relatedEnd->getResourceProperty()->getResourceType()->getFullName() . '_' . $relatedEnd->getResourceProperty()->getName(); } else { $reverseAssociationSetLookupKey = $relatedEnd->getResourceSet()->getName() . '_Null_' . $resourceType->getFullName() . '_' . $navigationProperty->getName(); } if (array_key_exists($reverseAssociationSetLookupKey, $this->_resourceAssociationSets)) { throw new InvalidOperationException(Messages::metadataAssociationTypeSetMultipleAssociationSetsForTheSameAssociationTypeMustNotReferToSameEndSets($this->_resourceAssociationSets[$reverseAssociationSetLookupKey]->getName(), $resourceAssociationSet->getName(), $relatedEnd->getResourceSet()->getName())); } $this->_resourceAssociationSets[$associationSetLookupKey] = $resourceAssociationSet; $this->_resourceAssociationSets[$reverseAssociationSetLookupKey] = $resourceAssociationSet; return $resourceAssociationSet; }
/** * To check this relationship belongs to a specific resource set, type * and property * * @param ResourceSet $resourceSet Resource set for the association * end * @param ResourceType $resourceType Resource type for the association * end * @param ResourceProperty $resourceProperty Resource property for the * association end * * @return boolean */ public function isBelongsTo(ResourceSet $resourceSet, ResourceType $resourceType, ResourceProperty $resourceProperty) { return strcmp($resourceSet->getName(), $this->_resourceSet->getName()) == 0 && $this->_resourceType->isAssignableFrom($resourceType) && (is_null($resourceProperty) && is_null($this->_resourceProperty) || !is_null($resourceProperty) && !is_null($this->_resourceProperty) && strcmp($resourceProperty->getName(), $this->_resourceProperty->getName()) == 0); }
/** * Retrieve the complex type(s) used in the given resource type and cache them. * * @param ResourceType $resourceType The resource type to inspect * * @return void * * @throws InvalidOperationException If found any complex type bag property * with derived type(s) */ private function _populateComplexTypes(ResourceType $resourceType) { foreach ($resourceType->getPropertiesDeclaredOnThisType() as $property) { if ($property->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) { if ($property->isKindOf(ResourcePropertyKind::BAG)) { //Validate the bag complex type //as it should not have derived type if ($this->providersWrapper->hasDerivedTypes($resourceType)) { throw new InvalidOperationException(Messages::metadataResourceTypeSetBagOfComplexTypeWithDerivedTypes($resourceType->getFullName())); } } if ($this->_populateResourceTypes($property->getResourceType())) { $this->_populateComplexTypes($property->getResourceType()); } } } }
/** * Validate this KeyDescriptor, If valid, this function populates * _validatedNamedValues array with key as keyName and value as an array of * key value and key type. * * @param string $segmentAsString The segment in the form identifer * (keyPredicate) which this descriptor * represents * @param ResourceType $resourceType The type of the idenfier in the segment * * @return void * * @throws ODataException If validation fails. */ public function validate($segmentAsString, ResourceType $resourceType) { if ($this->isEmpty()) { $this->_validatedNamedValues = array(); return; } $keyProperties = $resourceType->getKeyProperties(); $keyPropertiesCount = count($keyProperties); if (!empty($this->_namedValues)) { if (count($this->_namedValues) != $keyPropertiesCount) { throw ODataException::createSyntaxError(Messages::keyDescriptorKeyCountNotMatching($segmentAsString, $keyPropertiesCount, count($this->_namedValues))); } foreach ($keyProperties as $keyName => $keyResourceProperty) { if (!array_key_exists($keyName, $this->_namedValues)) { $keysAsString = null; foreach (array_keys($keyProperties) as $key) { $keysAsString .= $key . ', '; } $keysAsString = rtrim($keysAsString, ' ,'); throw ODataException::createSyntaxError(Messages::keyDescriptorMissingKeys($segmentAsString, $keysAsString)); } $typeProvided = $this->_namedValues[$keyName][1]; $expectedType = $keyResourceProperty->getInstanceType(); if (!$expectedType->isCompatibleWith($typeProvided)) { throw ODataException::createSyntaxError(Messages::keyDescriptorInCompatibleKeyType($segmentAsString, $keyName, $expectedType->getFullTypeName(), $typeProvided->getFullTypeName())); } $this->_validatedNamedValues[$keyName] = $this->_namedValues[$keyName]; } } else { if (count($this->_positionalValues) != $keyPropertiesCount) { throw ODataException::createSyntaxError(Messages::keyDescriptorKeyCountNotMatching($segmentAsString, $keyPropertiesCount, count($this->_positionalValues))); } $i = 0; foreach ($keyProperties as $keyName => $keyResourceProperty) { $typeProvided = $this->_positionalValues[$i][1]; $expectedType = $keyResourceProperty->getInstanceType(); if (!$expectedType->isCompatibleWith($typeProvided)) { throw ODataException::createSyntaxError(Messages::keyDescriptorInCompatibleKeyTypeAtPosition($segmentAsString, $keyResourceProperty->getName(), $i, $expectedType->getFullTypeName(), $typeProvided->getFullTypeName())); } $this->_validatedNamedValues[$keyName] = $this->_positionalValues[$i]; $i++; } } }