/** * Construct new instance of ResourceAssociationSetEnd * Note: The $resourceSet represents collection of an entity, The * $resourceType can be this entity's type or type of any of the * base resource of this entity, on which the navigation property * represented by $resourceProperty is defined. * * @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 * * @throws \InvalidArgumentException */ public function __construct(ResourceSet $resourceSet, ResourceType $resourceType, $resourceProperty) { if (!is_null($resourceProperty) && !$resourceProperty instanceof ResourceProperty) { throw new \InvalidArgumentException(Messages::resourceAssociationSetPropertyMustBeNullOrInsatnceofResourceProperty('$resourceProperty')); } if (!is_null($resourceProperty) && (is_null($resourceType->tryResolvePropertyTypeByName($resourceProperty->getName())) || $resourceProperty->getKind() != ResourcePropertyKind::RESOURCE_REFERENCE && $resourceProperty->getKind() != ResourcePropertyKind::RESOURCESET_REFERENCE)) { throw new \InvalidArgumentException(Messages::resourceAssociationSetEndPropertyMustBeNavigationProperty($resourceProperty->getName(), $resourceType->getFullName())); } if (!$resourceSet->getResourceType()->isAssignableFrom($resourceType) && !$resourceType->isAssignableFrom($resourceSet->getResourceType())) { throw new \InvalidArgumentException(Messages::resourceAssociationSetEndResourceTypeMustBeAssignableToResourceSet($resourceType->getFullName(), $resourceSet->getName())); } $this->_resourceSet = $resourceSet; $this->_resourceType = $resourceType; $this->_resourceProperty = $resourceProperty; }
/** * Write value of a bag instance. * * @param array/NULL &$BagValue Bag value to write. * @param string $propertyName Property name of the bag. * @param ResourceType &$resourceType Type describing the * bag value. * @param string $relativeUri Relative Url to the bag. * @param ODataPropertyContent &$odataPropertyContent On return, this object * will hold bag value which * can be used by writers. * * @return void */ private function _writeBagValue(&$BagValue, $propertyName, ResourceType &$resourceType, $relativeUri, ODataPropertyContent &$odataPropertyContent) { $bagItemResourceTypeKind = $resourceType->getResourceTypeKind(); $this->assert($bagItemResourceTypeKind == ResourceTypeKind::PRIMITIVE || $bagItemResourceTypeKind == ResourceTypeKind::COMPLEX, '$bagItemResourceTypeKind == ResourceTypeKind::PRIMITIVE || $bagItemResourceTypeKind == ResourceTypeKind::COMPLEX'); $odataProperty = new ODataProperty(); $odataProperty->name = $propertyName; $odataProperty->typeName = 'Collection(' . $resourceType->getFullName() . ')'; if (is_null($BagValue) || is_array($BagValue) && empty($BagValue)) { $odataProperty->value = null; } else { $odataBagContent = new ODataBagContent(); foreach ($BagValue as $itemValue) { if (!is_null($itemValue)) { if ($bagItemResourceTypeKind == ResourceTypeKind::PRIMITIVE) { $primitiveValueAsString = null; $this->_primitiveToString($resourceType, $itemValue, $primitiveValueAsString); $odataBagContent->propertyContents[] = $primitiveValueAsString; } else { if ($bagItemResourceTypeKind == ResourceTypeKind::COMPLEX) { $complexContent = new ODataPropertyContent(); $actualType = $this->_complexObjectToContent($itemValue, $propertyName, $resourceType, $relativeUri, $complexContent); //TODO add type in case of base type $odataBagContent->propertyContents[] = $complexContent; } } } } $odataProperty->value = $odataBagContent; } $odataPropertyContent->odataProperty[] = $odataProperty; }
/** * Gets full name of this type in EDM namespace * Note: implementation of IType::getFullTypeName * * @return string */ public function getFullTypeName() { return $this->_resourceType->getFullName(); }
/** * Gets the visible resource properties for the given resource type from * the given resource set wrapper. * * @param ResourceSetWrapper &$resourceSetWrapper Resource set wrapper in * question. * @param ResourceType &$resourceType Resource type in question. * * @return array(string, ResourceProperty) Collection of visible resource * properties from the given resource set wrapper and resource type. */ public function getResourceProperties(ResourceSetWrapper &$resourceSetWrapper, ResourceType &$resourceType) { if ($resourceType->getResourceTypeKind() == ResourceTypeKind::ENTITY) { $cacheKey = $resourceSetWrapper->getName() . '_' . $resourceType->getFullName(); if (array_key_exists($cacheKey, $this->_resourcePropertyCache)) { return $this->_resourcePropertyCache[$cacheKey]; } $this->_resourcePropertyCache[$cacheKey] = array(); foreach ($resourceType->getAllProperties() as $resourceProperty) { //Check whether this is a visible navigation property if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY && !is_null($this->getResourceSetWrapperForNavigationProperty($resourceSetWrapper, $resourceType, $resourceProperty))) { $this->_resourcePropertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty; } else { //primitive, bag or complex property $this->_resourcePropertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty; } } return $this->_resourcePropertyCache[$cacheKey]; } else { //Complex resource type return $resourceType->getAllProperties(); } }
/** * 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 * MetadataQueryProviderWrapper::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->metadataQueryproviderWrapper->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 //MetadataQueryproviderWrapper::getResourceAssociationSet //causes the metadata wrapper to check the visibility of //related resource set and cache the corrosponding wrapper. //If found invisible it would have return NULL, //which we are any way handling above. $relatedResourceSetWrapper = $this->metadataQueryproviderWrapper->validateResourceSetAndGetWrapper($relatedEnd->getResourceSet()); $reverseResourceAssociationSet = $this->metadataQueryproviderWrapper->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 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; }
/** * test ResourceType class */ public function testResourceType() { try { $exceptionThrown = false; try { ResourceType::getPrimitiveResourceType(TypeCode::VOID); } catch (\InvalidArgumentException $exception) { $exceptionThrown = true; $this->assertStringEndsWith('is not a valid EdmPrimitiveType Enum value', $exception->getMessage()); } if (!$exceptionThrown) { $this->fail('An expected InvalidArgumentException for \'EdmPrimitiveType\' has not been raised'); } $int16ResType = new ResourceType(new Int16(), ResourceTypeKind::PRIMITIVE, 'Int16', 'Edm'); $exceptionThrown = false; try { $int32ResType = new ResourceType(new Int32(), ResourceTypeKind::PRIMITIVE, 'Int32', 'Edm', $int16ResType); } catch (\InvalidArgumentException $exception) { $this->AssertEquals('Primitive type cannot have base type', $exception->getMessage()); $exceptionThrown = true; } if (!$exceptionThrown) { $this->fail('An expected InvalidArgumentException for \'basetype\' has not been raised'); } $exceptionThrown = false; try { $int32ResType = new ResourceType(new Int32(), ResourceTypeKind::PRIMITIVE, 'Int32', 'Edm', null, true); } catch (\InvalidArgumentException $exception) { $this->AssertEquals('Primitive type cannot be abstract', $exception->getMessage()); $exceptionThrown = true; } if (!$exceptionThrown) { $this->fail('An expected InvalidArgumentException for \'abstract\' has not been raised'); } $exceptionThrown = false; try { $int32ResType = new ResourceType(null, ResourceTypeKind::PRIMITIVE, 'Int32', 'Edm'); } catch (\InvalidArgumentException $exception) { $this->assertStringEndsWith('should be an \'IType\' implementor instance', $exception->getMessage()); $exceptionThrown = true; } if (!$exceptionThrown) { $this->fail('An expected InvalidArgumentException for \'IType\' has not been raised'); } $exceptionThrown = false; try { $customerResType = new ResourceType(null, ResourceTypeKind::ENTITY, 'Customer', 'Northwind'); } catch (\InvalidArgumentException $exception) { $this->assertStringEndsWith('argument should be an \'ReflectionClass\' instance', $exception->getMessage()); $exceptionThrown = true; } if (!$exceptionThrown) { $this->fail('An expected InvalidArgumentException for \'ReflectionClass\' has not been raised'); } $customerResType = new ResourceType(new ReflectionClass('Customer2'), ResourceTypeKind::ENTITY, 'Customer', 'Northwind'); $this->AssertEquals($customerResType->getName(), 'Customer'); $this->AssertEquals($customerResType->getFullName(), 'Northwind.Customer'); $this->assertTrue($customerResType->getInstanceType() instanceof \ReflectionClass); $this->AssertEquals($customerResType->getNamespace(), 'Northwind'); $this->AssertEquals($customerResType->getResourceTypeKind(), ResourceTypeKind::ENTITY); $this->AssertEquals($customerResType->isMediaLinkEntry(), false); $exceptionThrown = false; try { $customerResType->validateType(); } catch (InvalidOperationException $exception) { $this->assertStringEndsWith('Please make sure the key properties are defined for this entity type', $exception->getMessage()); $exceptionThrown = true; } if (!$exceptionThrown) { $this->fail('An expected InvalidOperationException for \'No key defined\' has not been raised'); } $exceptionThrown = false; try { $int32ResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::INT32); $primitiveResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::STRING); $testProperty = new ResourceProperty('test', null, ResourcePropertyKind::PRIMITIVE, $primitiveResourceType); $int32ResourceType->addProperty($testProperty); } catch (InvalidOperationException $exception) { $this->assertStringEndsWith('ResourceType instances with a ResourceTypeKind equal to \'Primitive\'', $exception->getMessage()); $exceptionThrown = true; } if (!$exceptionThrown) { $this->fail('An expected InvalidOperationException for \'property on primitive\' has not been raised'); } $stringResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::STRING); $customerIDPrimProperty = new ResourceProperty('CustomerID', null, ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY, $stringResourceType); $customerNamePrimProperty = new ResourceProperty('CustomerName', null, ResourcePropertyKind::PRIMITIVE, $stringResourceType); $intResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::INT32); $ratingPrimProperty = new ResourceProperty('Rating', null, ResourcePropertyKind::PRIMITIVE, $intResourceType); $addressResType = new ResourceType(new ReflectionClass('Address2'), ResourceTypeKind::COMPLEX, 'Address', 'Northwind'); $exceptionThrown = false; try { $booleanResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::BOOLEAN); $isPrimaryPrimProperty = new ResourceProperty('IsPrimary', null, ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY, $booleanResourceType); $addressResType->addProperty($isPrimaryPrimProperty); } catch (InvalidOperationException $exception) { $this->assertStringEndsWith('ResourceType instances with a ResourceTypeKind equal to \'EntityType\'', $exception->getMessage()); $exceptionThrown = true; } if (!$exceptionThrown) { $this->fail('An expected InvalidOperationException for \'Key on non-entity\' has not been raised'); } $booleanResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::BOOLEAN); $isPrimaryPrimProperty = new ResourceProperty('IsPrimary', null, ResourcePropertyKind::PRIMITIVE, $booleanResourceType); $addressResType->addProperty($isPrimaryPrimProperty); $exceptionThrown = false; try { $addressResType->addProperty($isPrimaryPrimProperty); } catch (InvalidOperationException $exception) { $this->assertStringStartsWith('Property with same name \'IsPrimary\' already exists in type \'Address\'', $exception->getMessage()); $exceptionThrown = true; } if (!$exceptionThrown) { $this->fail('An expected InvalidArgumentException for \'Property duplication\' has not been raised'); } $exceptionThrown = false; try { $addressResType->setMediaLinkEntry(true); } catch (InvalidOperationException $exception) { $exceptionThrown = true; $this->assertStringStartsWith('Cannot apply the HasStreamAttribute', $exception->getMessage()); } if (!$exceptionThrown) { $this->fail('An expected InvalidOperationException for \'MLE on non-entity\' has not been raised'); } $customerAdrComplexType = new ResourceProperty('Address', null, ResourcePropertyKind::COMPLEX_TYPE, $addressResType); $customerResType->addProperty($customerIDPrimProperty); $customerResType->addProperty($customerNamePrimProperty); $customerResType->addProperty($ratingPrimProperty); $customerResType->addProperty($customerAdrComplexType); $customerResType->validateType(); $customerProperties = $customerResType->getPropertiesDeclaredOnThisType(); $this->AssertEquals(count($customerProperties), 4); $customerAllProperties = $customerResType->getAllProperties(); $this->AssertEquals(count($customerProperties), count($customerAllProperties)); $keys = array('CustomerID', 'CustomerName', 'Rating', 'Address'); $i = 0; foreach ($customerAllProperties as $key => $customerProperty) { $this->AssertEquals($key, $keys[$i++]); } $entityKeys = array('CustomerID'); $customerKeyProperties = $customerResType->getKeyProperties(); $i = 0; foreach ($customerKeyProperties as $key => $customerKeyProperty) { $this->AssertEquals($key, $entityKeys[$i++]); } $this->AssertEquals(count($customerResType->getETagProperties()), 0); $this->AssertEquals($customerResType->tryResolvePropertyTypeByName('PropNotExists'), null); $property = $customerResType->tryResolvePropertyTypeByName('CustomerName'); $this->AssertNotEquals($property, null); $this->AssertEquals($property->getName(), 'CustomerName'); $employeeResType = new ResourceType(new ReflectionClass('Employee2'), ResourceTypeKind::ENTITY, 'Employee', 'Northwind'); $stringResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::STRING); $employeeResType->addProperty(new ResourceProperty('EmployeeID', null, ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY, $stringResourceType)); $employeeResType->addProperty(new ResourceProperty('Emails', null, ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::BAG, $stringResourceType)); $employeeResType->setMediaLinkEntry(true); $employeeResType->addNamedStream(new ResourceStreamInfo('ThumNail_64X64')); $exceptionThrown = false; try { $employeeResType->addNamedStream(new ResourceStreamInfo('ThumNail_64X64')); } catch (InvalidOperationException $exception) { $exceptionThrown = true; $this->assertStringStartsWith('Named stream with the name \'ThumNail_64X64\' already exists in type \'Employee\'', $exception->getMessage()); } if (!$exceptionThrown) { $this->fail('An expected InvalidOperationException for \'named stream duplication\' has not been raised'); } $this->AssertEquals($employeeResType->hasNamedStream(), true); $b = array(); $this->AssertEquals($employeeResType->hasBagProperty($b), true); $namedStreams = $employeeResType->getAllNamedStreams(); $this->AssertEquals(count($namedStreams), 1); $this->AssertTrue(array_key_exists('ThumNail_64X64', $namedStreams)); $name = $employeeResType->tryResolveNamedStreamByName('ThumNail_64X64')->getName(); $this->AssertEquals($name, 'ThumNail_64X64'); } catch (\Exception $exception) { $this->fail('An unexpected Exception has been raised' . $exception->getMessage()); } }