/**
  * 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;
 }
 /**
  * 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();
 }
 /**
  * test ResourceType class
  */
 public function testResourceType()
 {
     $exceptionThrown = false;
     try {
         ResourceType::getPrimitiveResourceType(TypeCode::VOID);
         $this->fail('An expected InvalidArgumentException for \'EdmPrimitiveType\' has not been raised');
     } catch (\InvalidArgumentException $exception) {
         $this->assertStringEndsWith('is not a valid EdmPrimitiveType Enum value', $exception->getMessage());
     }
     $int16ResType = new ResourceType(new Int16(), ResourceTypeKind::PRIMITIVE, 'Int16', 'Edm');
     try {
         $int32ResType = new ResourceType(new Int32(), ResourceTypeKind::PRIMITIVE, 'Int32', 'Edm', $int16ResType);
         $this->fail('An expected InvalidArgumentException for \'basetype\' has not been raised');
     } catch (\InvalidArgumentException $exception) {
         $this->AssertEquals('Primitive type cannot have base type', $exception->getMessage());
     }
     try {
         $int32ResType = new ResourceType(new Int32(), ResourceTypeKind::PRIMITIVE, 'Int32', 'Edm', null, true);
         $this->fail('An expected InvalidArgumentException for \'abstract\' has not been raised');
     } catch (\InvalidArgumentException $exception) {
         $this->AssertEquals('Primitive type cannot be abstract', $exception->getMessage());
     }
     try {
         $int32ResType = new ResourceType(null, ResourceTypeKind::PRIMITIVE, 'Int32', 'Edm');
         $this->fail('An expected InvalidArgumentException for \'IType\' has not been raised');
     } catch (\InvalidArgumentException $exception) {
         $this->assertStringEndsWith('should be an \'IType\' implementor instance', $exception->getMessage());
     }
     try {
         $customerResType = new ResourceType(null, ResourceTypeKind::ENTITY, 'Customer', 'Northwind');
         $this->fail('An expected InvalidArgumentException for \'ReflectionClass\' has not been raised');
     } catch (\InvalidArgumentException $exception) {
         $this->assertStringEndsWith('argument should be an \'ReflectionClass\' instance', $exception->getMessage());
     }
     $customerResType = new ResourceType(new \ReflectionClass('UnitTests\\POData\\Facets\\NorthWind1\\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);
     try {
         $customerResType->validateType();
         $this->fail('An expected InvalidOperationException for \'No key defined\' has not been raised');
     } catch (InvalidOperationException $exception) {
         $this->assertStringEndsWith('Please make sure the key properties are defined for this entity type', $exception->getMessage());
     }
     $int32ResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::INT32);
     $primitiveResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::STRING);
     $testProperty = new ResourceProperty('test', null, ResourcePropertyKind::PRIMITIVE, $primitiveResourceType);
     try {
         $int32ResourceType->addProperty($testProperty);
         $this->fail('An expected InvalidOperationException for \'property on primitive\' has not been raised');
     } catch (InvalidOperationException $exception) {
         $this->assertStringEndsWith('ResourceType instances with a ResourceTypeKind equal to \'Primitive\'', $exception->getMessage());
     }
     $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('UnitTests\\POData\\Facets\\NorthWind1\\Address2'), ResourceTypeKind::COMPLEX, 'Address', 'Northwind');
     $booleanResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::BOOLEAN);
     $isPrimaryPrimProperty = new ResourceProperty('IsPrimary', null, ResourcePropertyKind::PRIMITIVE | ResourcePropertyKind::KEY, $booleanResourceType);
     try {
         $addressResType->addProperty($isPrimaryPrimProperty);
         $this->fail('An expected InvalidOperationException for \'Key on non-entity\' has not been raised');
     } catch (InvalidOperationException $exception) {
         $this->assertStringEndsWith('ResourceType instances with a ResourceTypeKind equal to \'EntityType\'', $exception->getMessage());
     }
     $booleanResourceType = ResourceType::getPrimitiveResourceType(EdmPrimitiveType::BOOLEAN);
     $isPrimaryPrimProperty = new ResourceProperty('IsPrimary', null, ResourcePropertyKind::PRIMITIVE, $booleanResourceType);
     $addressResType->addProperty($isPrimaryPrimProperty);
     try {
         $addressResType->addProperty($isPrimaryPrimProperty);
         $this->fail('An expected InvalidArgumentException for \'Property duplication\' has not been raised');
     } catch (InvalidOperationException $exception) {
         $this->assertStringStartsWith('Property with same name \'IsPrimary\' already exists in type \'Address\'', $exception->getMessage());
     }
     try {
         $addressResType->setMediaLinkEntry(true);
         $this->fail('An expected InvalidOperationException for \'MLE on non-entity\' has not been raised');
     } catch (InvalidOperationException $exception) {
         $this->assertStringStartsWith('Cannot apply the HasStreamAttribute', $exception->getMessage());
     }
     $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->resolveProperty('PropNotExists'), null);
     $property = $customerResType->resolveProperty('CustomerName');
     $this->AssertNotEquals($property, null);
     $this->AssertEquals($property->getName(), 'CustomerName');
     $employeeResType = new ResourceType(new \ReflectionClass('UnitTests\\POData\\Facets\\NorthWind1\\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'));
     try {
         $employeeResType->addNamedStream(new ResourceStreamInfo('ThumNail_64X64'));
         $this->fail('An expected InvalidOperationException for \'named stream duplication\' has not been raised');
     } catch (InvalidOperationException $exception) {
         $this->assertStringStartsWith('Named stream with the name \'ThumNail_64X64\' already exists in type \'Employee\'', $exception->getMessage());
     }
     $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');
 }
Exemple #5
0
 /**
  * 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;
 }