/** * 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; }
/** * Iterate over the resource type of the given resource set, * derived resource types base resource types and complex types * used in these resource types and cache them. * * @param ResourceSetWrapper $resourceSetWrapper The resource set to inspect * * @return void * * @throws InvalidOperationException Throws exception in following cases: * (1) If IDSMP::getDerivedTypes returns any type other than null or array * (2) If Named streams are found on derived types */ private function _populateResourceTypeForSet(ResourceSetWrapper $resourceSetWrapper) { $derivedTypes = $this->providersWrapper->getDerivedTypes($resourceSetWrapper->getResourceType()); //Populate Resource type for derived types and //complex types in derived types foreach ($derivedTypes as $derivedType) { if ($derivedType->hasNamedStream()) { throw new InvalidOperationException(Messages::metadataResourceTypeSetNamedStreamsOnDerivedEntityTypesNotSupported($resourceSetWrapper->getName(), $derivedType->getFullName())); } $this->_populateResourceTypes($derivedType); $this->_populateComplexTypes($derivedType); } //Populate Resource type for for this type and //base types and complex types in this type and base types $resourceType = $resourceSetWrapper->getResourceType(); while ($resourceType != null) { $this->_populateResourceTypes($resourceType); $this->_populateComplexTypes($resourceType); $resourceType = $resourceType->getBaseType(); } }
/** * Gets the visible resource properties for the given resource type from the given resource set wrapper. * * @param ResourceSetWrapper $setWrapper Resource set wrapper in question. * @param ResourceType $resourceType Resource type in question. * @return ResourceProperty[] Collection of visible resource properties from the given resource set wrapper and resource type. */ public function getResourceProperties(ResourceSetWrapper $setWrapper, ResourceType $resourceType) { if ($resourceType->getResourceTypeKind() != ResourceTypeKind::ENTITY) { //Complex resource type return $resourceType->getAllProperties(); } //TODO: move this to doctrine annotations $cacheKey = $setWrapper->getName() . '_' . $resourceType->getFullName(); if (!array_key_exists($cacheKey, $this->propertyCache)) { //Fill the cache $this->propertyCache[$cacheKey] = array(); foreach ($resourceType->getAllProperties() as $resourceProperty) { //Check whether this is a visible navigation property //TODO: is this broken?? see #87 if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY && !is_null($this->getResourceSetWrapperForNavigationProperty($setWrapper, $resourceType, $resourceProperty))) { $this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty; } else { //primitive, bag or complex property $this->propertyCache[$cacheKey][$resourceProperty->getName()] = $resourceProperty; } } } return $this->propertyCache[$cacheKey]; }