/** * Write an entity type and associated attributes. * * @param ResourceType $resourceType Resource type * @param array $associationTypesInResourceTypeNamespace Collection of * association types for the given resource types * array(string, AssociationType) * * @return nothing */ private function _writeEntityType(ResourceType $resourceType, $associationTypesInResourceTypeNamespace) { $this->_iOdataWriter->startElement(ODataConstants::ENTITY_TYPE); $this->_iOdataWriter->writeAttribute(ODataConstants::NAME, $resourceType->getName()); if ($resourceType->isAbstract()) { $this->_iOdataWriter->writeAttribute(ODataConstants::ABSTRACT1, "true"); } if ($resourceType->isMediaLinkEntry() && (!$resourceType->hasBaseType() || $resourceType->hasBaseType() && $resourceType->getBaseType()->isMediaLinkEntry())) { $this->_iOdataWriter->writeAttributeNs(ODataConstants::ODATA_METADATA_NAMESPACE_PREFIX, ODataConstants::DATAWEB_ACCESS_HASSTREAM_ATTRIBUTE, null, "true"); } if ($resourceType->hasBaseType()) { $this->_iOdataWriter->writeAttribute(ODataConstants::BASE_TYPE, $resourceType->getBaseType()->getFullName()); } else { $this->_iOdataWriter->startElement(ODataConstants::KEY); foreach ($resourceType->getKeyProperties() as $resourceProperty) { $this->_iOdataWriter->startElement(ODataConstants::PROPERTY_REF); $this->_iOdataWriter->writeAttribute(ODataConstants::NAME, $resourceProperty->getName()); $this->_iOdataWriter->endElement(); } $this->_iOdataWriter->endElement(); } $this->_writeProperties($resourceType, $associationTypesInResourceTypeNamespace); $this->_writeNamedStreams($resourceType); $this->_iOdataWriter->endElement(); }
/** * 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()); } }
/** * 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) { 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, ' ,'); ODataException::createSyntaxError(Messages::keyDescriptorMissingKeys($segmentAsString, $keysAsString)); } $typeProvided = $this->_namedValues[$keyName][1]; $expectedType = $keyResourceProperty->getInstanceType(); if (!$expectedType->isCompatibleWith($typeProvided)) { ODataException::createSyntaxError(Messages::keyDescriptorInCompatibleKeyType($segmentAsString, $keyName, $expectedType->getFullTypeName(), $typeProvided->getFullTypeName())); } $this->_validatedNamedValues[$keyName] = $this->_namedValues[$keyName]; } } else { if (count($this->_positionalValues) != $keyPropertiesCount) { 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)) { ODataException::createSyntaxError(Messages::keyDescriptorInCompatibleKeyTypeAtPosition($segmentAsString, $keyResourceProperty->getName(), $i, $expectedType->getFullTypeName(), $typeProvided->getFullTypeName())); } $this->_validatedNamedValues[$keyName] = $this->_positionalValues[$i]; $i++; } } }
/** * Builds the key for the given entity instance. * Note: The generated key can be directly used in the uri, * this function will perform * required escaping of characters, for example: * Ships(ShipName='Antonio%20Moreno%20Taquer%C3%ADa',ShipID=123), * Note to method caller: Don't do urlencoding on * return value of this method as it already encoded. * * @param mixed &$entityInstance Entity instance for which * key value needs to be prepared. * @param ResourceType &$resourceType Resource type instance containing * metadata about the instance. * @param string $containerName Name of the entity set that * the entity instance belongs to. * * @return string Key for the given resource, with values * encoded for use in a URI. */ protected function getEntryInstanceKey(&$entityInstance, ResourceType &$resourceType, $containerName) { $keyProperties = $resourceType->getKeyProperties(); $this->assert(count($keyProperties) != 0, 'count($keyProperties) != 0'); $keyString = $containerName . '('; $comma = null; foreach ($keyProperties as $keyName => $resourceProperty) { $keyType = $resourceProperty->getInstanceType(); $this->assert(array_search('ODataProducer\\Providers\\Metadata\\Type\\IType', class_implements($keyType)) !== false, 'array_search(\'ODataProducer\\Providers\\Metadata\\Type\\IType\', class_implements($keyType)) !== false'); $keyValue = $this->getPropertyValue($entityInstance, $resourceType, $resourceProperty); if (is_null($keyValue)) { ODataException::createInternalServerError(Messages::badQueryNullKeysAreNotSupported($resourceType->getName(), $keyName)); } $keyValue = $keyType->convertToOData($keyValue); $keyString .= $comma . $keyName . '=' . $keyValue; $comma = ','; } $keyString .= ')'; return $keyString; }