/** * * @param <string> $type * Constructor */ public function ClientType($type) { $this->_attributes = array(); $this->_properties = array(); $this->_navigationProperties = array(); $this->_sortedEPMProperties = array(); $targetPathToCount = array(); try { $rClass = new ReflectionClass($type); $this->_hasEPM = false; $this->_attributes = Utility::getAttributes($rClass); $sourceProperty = null; if (array_key_exists('FC_SourcePath', $this->_attributes)) { $this->_hasEPM = true; $sourceProperty = $this->_attributes['FC_SourcePath']; } $properties = $rClass->getProperties(); foreach ($properties as $property) { if ($property->isPublic()) { $attributes = Utility::getAttributes($property); $propertyName = $property->name; if ($sourceProperty != null && $sourceProperty == $propertyName) { ValidateEPMAttributes($this->_attributes, $attributes, $sourceProperty, false); } if (isset($attributes['Type']) && $attributes['Type'] == 'EntityProperty') { $propertyObj = new Property($propertyName, $attributes); $this->_properties[$propertyName] = $propertyObj; if ($propertyObj->hasEPM($syn)) { $this->_hasEPM = true; $attrs = $propertyObj->getAttributes(); if ($syn) { $targetPath = SyndicationItemProperty::GetSyndicationItemPathNoNS($attrs['FC_TargetPath']); } else { $targetPath = $attrs['FC_TargetPathNS']; if (isset($attrs['NodeAttribute'])) { $targetPath .= '/@' . $attrs['NodeAttribute']; } } $targetPathToCount[$targetPath] = substr_count($targetPath, "/"); } } else { if (isset($attributes['Type']) && $attributes['Type'] == 'NavigationProperty') { $this->_navigationProperties[$propertyName] = new Property($propertyName, $attributes); } } } } asort($targetPathToCount); $properties = $this->_properties; foreach ($targetPathToCount as $key => $value) { foreach ($properties as $property) { $syn = false; $targetPath = null; if ($property->hasEPM($syn)) { $attrs = $property->getAttributes(); if ($syn) { $targetPath = SyndicationItemProperty::GetSyndicationItemPathNoNS($attrs['FC_TargetPath']); } else { $targetPath = $attrs['FC_TargetPathNS']; if (isset($attrs['NodeAttribute'])) { $targetPath .= '/@' . $attrs['NodeAttribute']; } } if ($key == $targetPath) { $this->_sortedEPMProperties[] = $property; } } } } } catch (ReflectionException $exception) { throw new InvalidOperation('ReflectionException in ClientType constructor'); } }
/** * To create changeset body for an entity in ATOMPub format. * * @param ResourceBox $resourceBox * @param boolean $newline * @return string * @throws InvalidOperation, InternalError */ protected function CreateChangeSetBodyForResource($resourceBox, $newline) { $syndicationUpdated = false; if (EntityStates::Deleted == $resourceBox->State) { return null; } if (EntityStates::Added != $resourceBox->State && EntityStates::Modified != $resourceBox->State) { throw new InternalError(Resource::UnexpectdEntityState); } $changesetBodyForResource = null; Utility::WriteLine($changesetBodyForResource, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>"); Utility::WriteLine($changesetBodyForResource, "<entry xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns=\"http://www.w3.org/2005/Atom\">"); $object = $resourceBox->getResource(); $entityName = get_class($object); $type = ClientType::Create($entityName); $nullCFProperties = array(); $CF_SyndicationXML = null; $CF_NonSyndicationXML = null; $this->HandleNCharProperties($type, $object); //Check this Client Type has Syndication or Custom Property mapping, if so //build the syndication XML/Custom XML. if ($type->hasEPM()) { $epmProperties = $type->getRawSortedEPMProperties(); $FC_Synd_dom = new DOMDocument(); $FC_NonSynd_dom = new DOMDocument(); foreach ($epmProperties as $epmProperty) { $synd = false; if ($epmProperty->hasEPM($synd)) { $propertyName = $epmProperty->getName(); $attributes = $epmProperty->getAttributes(); $refProperty = new ReflectionProperty($object, $propertyName); $propertyValue = $refProperty->getValue($object); if ($synd) { if ($attributes['FC_TargetPath'] == 'SyndicationUpdated') { $syndicationUpdated = true; $propertyValue = Utility::TimeInISO8601(); } if (is_null($propertyValue)) { $nullCFProperties[] = $propertyName; } $path = SyndicationItemProperty::GetSyndicationItemPathNoNS($attributes['FC_TargetPath']); XMLBuilder::BuildDOMFromPath($FC_Synd_dom, $path, $propertyValue, '', '', false); } else { if (is_null($propertyValue)) { $nullCFProperties[] = $propertyName; } XMLBuilder::BuildDOMFromPath($FC_NonSynd_dom, $attributes['FC_TargetPath'], $propertyValue, $attributes['FC_NsPrefix'], $attributes['FC_NsUri'], true); } } } $CF_SyndicationXML = trim(str_replace('<?xml version="1.0"?>', '', $FC_Synd_dom->SaveXML())); $CF_NonSyndicationXML = trim(str_replace('<?xml version="1.0"?>', '', $FC_NonSynd_dom->SaveXML())); } if (!empty($CF_SyndicationXML)) { Utility::WriteLine($changesetBodyForResource, $CF_SyndicationXML); if (!$syndicationUpdated) { Utility::WriteLine($changesetBodyForResource, '<updated>' . Utility::TimeInISO8601() . '</updated>'); } } else { Utility::WriteLine($changesetBodyForResource, '<title />'); Utility::WriteLine($changesetBodyForResource, '<author>'); Utility::WriteLine($changesetBodyForResource, '<name />'); Utility::WriteLine($changesetBodyForResource, '</author>'); Utility::WriteLine($changesetBodyForResource, '<updated>' . Utility::TimeInISO8601() . '</updated>'); } if (EntityStates::Modified == $resourceBox->State) { $editLinkUri = $resourceBox->Identity; Utility::WriteLine($changesetBodyForResource, '<id>' . $editLinkUri . '</id>'); //While modifying, key properties cannot be null $keyPropertyNames = $type->geyKeyProperties(); foreach ($keyPropertyNames as $keyPropertyName) { $prop = new ReflectionProperty($object, $keyPropertyName); $propertyValue = $prop->getValue($object); if (empty($propertyValue) && !$this->_processingMediaLinkEntry) { throw new InvalidOperation(Resource::NullValueNotAllowedForKey . $keyPropertyName); } } } else { Utility::WriteLine($changesetBodyForResource, '<id />'); } if (!$resourceBox->MediaLinkEntry) { Utility::WriteLine($changesetBodyForResource, "<content type=\"application/xml\">"); } Utility::WriteLine($changesetBodyForResource, '<m:properties>'); $nonEpmProperties = $type->getRawNonEPMProperties(true); foreach ($nonEpmProperties as $nonEpmProperty) { $propertyName = $nonEpmProperty->getName(); $refProperty = new ReflectionProperty($object, $propertyName); $propertyValue = $refProperty->getValue($object); $body = $this->CheckAndCreateChangeSetBodyPartForComplexType($nonEpmProperty, $propertyValue); if ($body) { Utility::WriteLine($changesetBodyForResource, $body); continue; } $property = ''; // determine if the property is null and should be output accordingly // for numeric types, utilize a numeric value if ($propertyValue) { Utility::GetPropertyType($refProperty, $notNullable); if (!$notNullable) { $property = "<d:" . $propertyName . " " . "m:null=\"true\" />"; } elseif (strpos($edmType, 'Edm.Decimal') === 0) { $property = '<d:' . $propertyName . '>0.0M</d:' . $propertyName . '>'; } elseif (strpos($edmType, 'Edm.Double') === 0) { $property = '<d:' . $propertyName . '>0.0</d:' . $propertyName . '>'; } elseif (strpos($edmType, 'Edm.Int') === 0) { $property = '<d:' . $propertyName . '>0</d:' . $propertyName . '>'; } elseif (strpos($edmType, 'Edm.Single') === 0) { $property = '<d:' . $propertyName . '>0.0f</d:' . $propertyName . '>'; } else { /** * The following comment is from the original authors and remains until * further investigation can be made regarding proper behavior of * non-nullable types. */ //ex: In the case of OrderID, the ID is a autonumber, so user will not //specify this value, since its a nonnullable value we cant set null=true //property, in this case the correct property node should be //<d:OrderID">0</d:OrderID">, but instead of this we can also achieve the //same effect by not adding the property itself in xml continue; } } else { $attributes = $nonEpmProperty->getAttributes(); $edmType = ''; if (isset($attributes['EdmType']) && $attributes['EdmType'] != 'Edm.String') { $edmType = ' m:type="' . $attributes['EdmType'] . '"'; // wrap value in CDATA tag since strings may contain XML special characters $propertyValue = "<![CDATA[" . $propertyValue . "]]>"; } $property = '<d:' . $propertyName . $edmType . '>' . $propertyValue . '</d:' . $propertyName . '>'; } Utility::WriteLine($changesetBodyForResource, $property); } //Check for CF properties for which user has set null value. In this //case these properties should be added in the content section. foreach ($nullCFProperties as $nullCFProperty) { $refProperty = new ReflectionProperty($object, $propertyName); $property = "<d:" . $nullCFProperty . " " . "m:null=\"true\" />"; Utility::WriteLine($changesetBodyForResource, $property); } Utility::WriteLine($changesetBodyForResource, '</m:properties>'); if (!$resourceBox->MediaLinkEntry) { Utility::WriteLine($changesetBodyForResource, '</content>'); } //append CF Cutom XML if (!empty($CF_NonSyndicationXML)) { Utility::WriteLine($changesetBodyForResource, $CF_NonSyndicationXML); } Utility::WriteLine($changesetBodyForResource, '</entry>'); if ($newline) { Utility::WriteLine($changesetBodyForResource, null); } return $changesetBodyForResource; }