/** * 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; }
/** * * @param <string> $name * @param <array<key => value>> $attributes * Constructor */ public function Property($name, $attributes) { $this->_isSyndication = $this->_hasEPM = false; $this->_name = $name; $this->_attributes = $attributes; if (array_key_exists('FC_TargetPath', $this->_attributes)) { ValidateEPMAttributes($this->_attributes, $this->_attributes, $this->_name, true); $this->_hasEPM = true; $this->_isSyndication = SyndicationItemProperty::IsSyndicationItem($this->_attributes['FC_TargetPath']); if (!$this->_isSyndication) { $attribute = null; $segments = explode("/", $this->_attributes['FC_TargetPath']); $segment_count = count($segments); if ($segments[$segment_count - 1][0] == '@') { $attribute = ltrim($segments[$segment_count - 1], '@'); $this->_attributes['NodeAttribute'] = $attribute; unset($segments[$segment_count - 1]); $segment_count--; } $FC_TargetPathWithNS = null; $nsPrefix = $this->_attributes['FC_NsPrefix']; $FC_TargetPathWithNS = $nsPrefix . ":" . $segments[0]; for ($i = 1; $i < $segment_count; $i++) { $FC_TargetPathWithNS = $FC_TargetPathWithNS . "/" . $nsPrefix . ":" . $segments[$i]; } $this->_attributes['FC_TargetPathNS'] = $FC_TargetPathWithNS; } } }
protected function HandleProperties($xPath, $propertyQuery, $clientType, $object) { if ($clientType->hasEPM()) { $epmProperties = $clientType->getRawEPMProperties(); foreach ($epmProperties as $epmProperty) { $propertyName = $epmProperty->getName(); $attributes = $epmProperty->getAttributes(); $targetQuery = null; $synd = false; if ($epmProperty->hasEPM($synd)) { if ($synd) { $targetQuery = SyndicationItemProperty::GetSyndicationItemPathwithNS($attributes['FC_TargetPath']); } else { $targetQuery = $attributes['FC_TargetPathNS']; $xPath->registerNamespace($attributes['FC_NsPrefix'], $attributes['FC_NsUri']); } $nodes = $xPath->Query($targetQuery); if ($nodes->length) { $value = null; if (isset($attributes['NodeAttribute'])) { $attribute = $attributes['FC_NsPrefix'] . ":" . $attributes['NodeAttribute']; $value = self::GetAttribute($nodes->item(0), $attribute); if (is_null($value) && (isset($attributes['EdmType']) && ($attributes['EdmType'] == 'Edm.Int16' || $attributes['EdmType'] == 'Edm.Int32' || $attributes['EdmType'] == 'Edm.Int64'))) { $value = '0'; } } else { $value = null; if ($nodes->item(0)->hasChildNodes()) { $value = $nodes->item(0)->firstChild->textContent; } else { $value = $nodes->item(0)->nodeValue; } if (empty($value)) { $query1 = $propertyQuery . $propertyName; $nodes1 = $xPath->Query($query1); if ($nodes1->length) { $value1 = self::GetAttribute($nodes1->item(0), "m:null"); if ($value1 == 'true') { $value = null; } } } } $property = new ReflectionProperty($object, $propertyName); $property->setValue($object, $value); } else { //NOTE: Atom Entry not contains $targetQuery node its //an error, becase in the case of projection also //custmerizable feeds will be there. // } } } } $nonEpmProperties = $clientType->getRawNonEPMProperties(true); foreach ($nonEpmProperties as $nonEpmProperty) { $propertyName = $nonEpmProperty->getName(); $propertyAttributes = $nonEpmProperty->getAttributes(); //Now check for complex type. If type not start with 'Edm.' //it can be a complex type. if (isset($propertyAttributes['EdmType']) && strpos($propertyAttributes['EdmType'], 'Edm.') !== 0) { $complexPropertyObject = null; $complexPropertyName = ''; if ($this->CheckAndProcessComplexType($xPath, $propertyQuery, $propertyName, $complexPropertyName, $complexPropertyObject)) { $property = new ReflectionProperty($object, $complexPropertyName); $property->setValue($object, $complexPropertyObject); continue; } } $query = $propertyQuery . $propertyName; $nodes = $xPath->Query($query); if ($nodes->length) { $value = $nodes->item(0)->nodeValue; $property = new ReflectionProperty($object, $propertyName); $property->setValue($object, $value); } else { //NOTE: Atom Entry not contains the required property //not a bug projection can lead to this case } } }