Viewing file: Table.php (32.55 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /** * Copyright (c) 2009 - 2010, RealDolmen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of RealDolmen nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY RealDolmen ''AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL RealDolmen BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @category Microsoft * @package Microsoft_WindowsAzure * @subpackage Storage * @copyright Copyright (c) 2009 - 2010, RealDolmen (http://www.realdolmen.com) * @license http://phpazure.codeplex.com/license * @version $Id: Blob.php 14561 2009-05-07 08:05:12Z unknown $ */ if (!defined('W3TC')) { die(); }
/** * @see Microsoft_WindowsAzure_Credentials_CredentialsAbstract */ require_once 'Microsoft/WindowsAzure/Credentials/CredentialsAbstract.php';
/** * @see Microsoft_WindowsAzure_Credentials_SharedKey */ require_once 'Microsoft/WindowsAzure/Credentials/SharedKey.php';
/** * @see Microsoft_WindowsAzure_Credentials_SharedKeyLite */ require_once 'Microsoft/WindowsAzure/Credentials/SharedKeyLite.php';
/** * @see Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract */ require_once 'Microsoft/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php';
/** * @see Microsoft_Http_Client */ require_once 'Microsoft/Http/Client.php';
/** * @see Microsoft_Http_Response */ require_once 'Microsoft/Http/Response.php';
/** * @see Microsoft_WindowsAzure_Storage */ require_once 'Microsoft/WindowsAzure/Storage.php';
/** * @see Microsoft_WindowsAzure_Storage_BatchStorageAbstract */ require_once 'Microsoft/WindowsAzure/Storage/BatchStorageAbstract.php';
/** * @see Microsoft_WindowsAzure_Storage_TableInstance */ require_once 'Microsoft/WindowsAzure/Storage/TableInstance.php';
/** * @see Microsoft_WindowsAzure_Storage_TableEntity */ require_once 'Microsoft/WindowsAzure/Storage/TableEntity.php';
/** * @see Microsoft_WindowsAzure_Storage_DynamicTableEntity */ require_once 'Microsoft/WindowsAzure/Storage/DynamicTableEntity.php';
/** * @see Microsoft_WindowsAzure_Storage_TableEntityQuery */ require_once 'Microsoft/WindowsAzure/Storage/TableEntityQuery.php';
/** * @see Microsoft_WindowsAzure_Exception */ require_once 'Microsoft/WindowsAzure/Exception.php';
/** * @category Microsoft * @package Microsoft_WindowsAzure * @subpackage Storage * @copyright Copyright (c) 2009 - 2010, RealDolmen (http://www.realdolmen.com) * @license http://phpazure.codeplex.com/license */ class Microsoft_WindowsAzure_Storage_Table extends Microsoft_WindowsAzure_Storage_BatchStorageAbstract { /** * Throw Microsoft_WindowsAzure_Exception when a property is not specified in Windows Azure? * Defaults to true, making behaviour similar to Windows Azure StorageClient in .NET. * * @var boolean */ protected $_throwExceptionOnMissingData = true;
/** * Throw Microsoft_WindowsAzure_Exception when a property is not specified in Windows Azure? * Defaults to true, making behaviour similar to Windows Azure StorageClient in .NET. * * @param boolean $value */ public function setThrowExceptionOnMissingData($value = true) { $this->_throwExceptionOnMissingData = $value; }
/** * Throw Microsoft_WindowsAzure_Exception when a property is not specified in Windows Azure? */ public function getThrowExceptionOnMissingData() { return $this->_throwExceptionOnMissingData; }
/** * Creates a new Microsoft_WindowsAzure_Storage_Table instance * * @param string $host Storage host name * @param string $accountName Account name for Windows Azure * @param string $accountKey Account key for Windows Azure * @param boolean $usePathStyleUri Use path-style URI's * @param Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests */ public function __construct($host = Microsoft_WindowsAzure_Storage::URL_DEV_TABLE, $accountName = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT, $accountKey = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY, $usePathStyleUri = false, Microsoft_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null) { parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy);
// Always use SharedKeyLite authentication $this->_credentials = new Microsoft_WindowsAzure_Credentials_SharedKeyLite($accountName, $accountKey, $this->_usePathStyleUri);
// API version $this->_apiVersion = '2009-09-19'; }
/** * Check if a table exists * * @param string $tableName Table name * @return boolean */ public function tableExists($tableName = '') { if ($tableName === '') { throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); }
// List tables $tables = $this->listTables(); // 2009-09-19 does not support $this->listTables($tableName); all of a sudden... foreach ($tables as $table) { if ($table->Name == $tableName) { return true; } }
return false; }
/** * List tables * * @param string $nextTableName Next table name, used for listing tables when total amount of tables is > 1000. * @return array * @throws Microsoft_WindowsAzure_Exception */ public function listTables($nextTableName = '') { // Build query string $queryString = array(); if ($nextTableName != '') { $queryString[] = 'NextTableName=' . $nextTableName; } $queryString = self::createQueryStringFromArray($queryString);
// Perform request $response = $this->_performRequest('Tables', $queryString, Microsoft_Http_Client::GET, null, true); if ($response->isSuccessful()) { // Parse result $result = $this->_parseResponse($response);
if (!$result || !$result->entry) { return array(); }
$entries = null; if (count($result->entry) > 1) { $entries = $result->entry; } else { $entries = array($result->entry); }
// Create return value $returnValue = array(); foreach ($entries as $entry) { $tableName = $entry->xpath('.//m:properties/d:TableName'); $tableName = (string)$tableName[0];
$returnValue[] = new Microsoft_WindowsAzure_Storage_TableInstance( (string)$entry->id, $tableName, (string)$entry->link['href'], (string)$entry->updated ); }
// More tables? if (!is_null($response->getHeader('x-ms-continuation-NextTableName'))) { $returnValue = array_merge($returnValue, $this->listTables($response->getHeader('x-ms-continuation-NextTableName'))); }
return $returnValue; } else { throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } }
/** * Create table * * @param string $tableName Table name * @return Microsoft_WindowsAzure_Storage_TableInstance * @throws Microsoft_WindowsAzure_Exception */ public function createTable($tableName = '') { if ($tableName === '') { throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); }
// Generate request body $requestBody = '<?xml version="1.0" encoding="utf-8" standalone="yes"?> <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"> <title /> <updated>{tpl:Updated}</updated> <author> <name /> </author> <id /> <content type="application/xml"> <m:properties> <d:TableName>{tpl:TableName}</d:TableName> </m:properties> </content> </entry>';
$requestBody = $this->_fillTemplate($requestBody, array( 'BaseUrl' => $this->getBaseUrl(), 'TableName' => htmlspecialchars($tableName), 'Updated' => $this->isoDate(), 'AccountName' => $this->_accountName ));
// Add header information $headers = array(); $headers['Content-Type'] = 'application/atom+xml'; $headers['DataServiceVersion'] = '1.0;NetFx'; $headers['MaxDataServiceVersion'] = '1.0;NetFx';
// Perform request $response = $this->_performRequest('Tables', '', Microsoft_Http_Client::POST, $headers, true, $requestBody); if ($response->isSuccessful()) { // Parse response $entry = $this->_parseResponse($response);
$tableName = $entry->xpath('.//m:properties/d:TableName'); $tableName = (string)$tableName[0];
return new Microsoft_WindowsAzure_Storage_TableInstance( (string)$entry->id, $tableName, (string)$entry->link['href'], (string)$entry->updated ); } else { throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } }
/** * Create table if it does not exist * * @param string $tableName Table name * @throws Microsoft_WindowsAzure_Exception */ public function createTableIfNotExists($tableName = '') { if (!$this->tableExists($tableName)) { $this->createTable($tableName); } }
/** * Delete table * * @param string $tableName Table name * @throws Microsoft_WindowsAzure_Exception */ public function deleteTable($tableName = '') { if ($tableName === '') { throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); }
// Add header information $headers = array(); $headers['Content-Type'] = 'application/atom+xml';
// Perform request $response = $this->_performRequest('Tables(\'' . $tableName . '\')', '', Microsoft_Http_Client::DELETE, $headers, true, null); if (!$response->isSuccessful()) { throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } }
/** * Insert entity into table * * @param string $tableName Table name * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to insert * @return Microsoft_WindowsAzure_Storage_TableEntity * @throws Microsoft_WindowsAzure_Exception */ public function insertEntity($tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null) { if ($tableName === '') { throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); } if (is_null($entity)) { throw new Microsoft_WindowsAzure_Exception('Entity is not specified.'); }
// Generate request body $requestBody = '<?xml version="1.0" encoding="utf-8" standalone="yes"?> <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"> <title /> <updated>{tpl:Updated}</updated> <author> <name /> </author> <id /> <content type="application/xml"> <m:properties> {tpl:Properties} </m:properties> </content> </entry>';
$requestBody = $this->_fillTemplate($requestBody, array( 'Updated' => $this->isoDate(), 'Properties' => $this->_generateAzureRepresentation($entity) ));
// Add header information $headers = array(); $headers['Content-Type'] = 'application/atom+xml';
// Perform request $response = null; if ($this->isInBatch()) { $this->getCurrentBatch()->enlistOperation($tableName, '', Microsoft_Http_Client::POST, $headers, true, $requestBody); return null; } else { $response = $this->_performRequest($tableName, '', Microsoft_Http_Client::POST, $headers, true, $requestBody); } if ($response->isSuccessful()) { // Parse result $result = $this->_parseResponse($response);
$timestamp = $result->xpath('//m:properties/d:Timestamp'); $timestamp = (string)$timestamp[0];
$etag = $result->attributes('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); $etag = (string)$etag['etag'];
// Update properties $entity->setTimestamp($timestamp); $entity->setEtag($etag);
return $entity; } else { throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } }
/** * Delete entity from table * * @param string $tableName Table name * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to delete * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) * @throws Microsoft_WindowsAzure_Exception */ public function deleteEntity($tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false) { if ($tableName === '') { throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); } if (is_null($entity)) { throw new Microsoft_WindowsAzure_Exception('Entity is not specified.'); }
// Add header information $headers = array(); if (!$this->isInBatch()) { // http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/9e255447-4dc7-458a-99d3-bdc04bdc5474/ $headers['Content-Type'] = 'application/atom+xml'; } $headers['Content-Length'] = 0; if (!$verifyEtag) { $headers['If-Match'] = '*'; } else { $headers['If-Match'] = $entity->getEtag(); }
// Perform request $response = null; if ($this->isInBatch()) { $this->getCurrentBatch()->enlistOperation($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', Microsoft_Http_Client::DELETE, $headers, true, null); return null; } else { $response = $this->_performRequest($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', Microsoft_Http_Client::DELETE, $headers, true, null); } if (!$response->isSuccessful()) { throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } }
/** * Retrieve entity from table, by id * * @param string $tableName Table name * @param string $partitionKey Partition key * @param string $rowKey Row key * @param string $entityClass Entity class name* * @return Microsoft_WindowsAzure_Storage_TableEntity * @throws Microsoft_WindowsAzure_Exception */ public function retrieveEntityById($tableName = '', $partitionKey = '', $rowKey = '', $entityClass = 'Microsoft_WindowsAzure_Storage_DynamicTableEntity') { if ($tableName === '') { throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); } if ($partitionKey === '') { throw new Microsoft_WindowsAzure_Exception('Partition key is not specified.'); } if ($rowKey === '') { throw new Microsoft_WindowsAzure_Exception('Row key is not specified.'); } if ($entityClass === '') { throw new Microsoft_WindowsAzure_Exception('Entity class is not specified.'); }
// Check for combined size of partition key and row key // http://msdn.microsoft.com/en-us/library/dd179421.aspx if (strlen($partitionKey . $rowKey) >= 256) { // Start a batch if possible if ($this->isInBatch()) { throw new Microsoft_WindowsAzure_Exception('Entity cannot be retrieved. A transaction is required to retrieve the entity, but another transaction is already active.'); }
$this->startBatch(); }
// Fetch entities from Azure $result = $this->retrieveEntities( $this->select() ->from($tableName) ->wherePartitionKey($partitionKey) ->whereRowKey($rowKey), '', $entityClass );
// Return if (count($result) == 1) { return $result[0]; }
return null; }
/** * Create a new Microsoft_WindowsAzure_Storage_TableEntityQuery * * @return Microsoft_WindowsAzure_Storage_TableEntityQuery */ public function select() { return new Microsoft_WindowsAzure_Storage_TableEntityQuery(); }
/** * Retrieve entities from table * * @param string $tableName|Microsoft_WindowsAzure_Storage_TableEntityQuery Table name -or- Microsoft_WindowsAzure_Storage_TableEntityQuery instance * @param string $filter Filter condition (not applied when $tableName is a Microsoft_WindowsAzure_Storage_TableEntityQuery instance) * @param string $entityClass Entity class name * @param string $nextPartitionKey Next partition key, used for listing entities when total amount of entities is > 1000. * @param string $nextRowKey Next row key, used for listing entities when total amount of entities is > 1000. * @return array Array of Microsoft_WindowsAzure_Storage_TableEntity * @throws Microsoft_WindowsAzure_Exception */ public function retrieveEntities($tableName = '', $filter = '', $entityClass = 'Microsoft_WindowsAzure_Storage_DynamicTableEntity', $nextPartitionKey = null, $nextRowKey = null) { if ($tableName === '') { throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); } if ($entityClass === '') { throw new Microsoft_WindowsAzure_Exception('Entity class is not specified.'); }
// Convenience... if (class_exists($filter)) { $entityClass = $filter; $filter = ''; }
// Query string $queryString = '';
// Determine query if (is_string($tableName)) { // Option 1: $tableName is a string
// Append parentheses $tableName .= '()';
// Build query $query = array();
// Filter? if ($filter !== '') { $query[] = '$filter=' . Microsoft_WindowsAzure_Storage_TableEntityQuery::encodeQuery($filter); }
// Build queryString if (count($query) > 0) { $queryString = '?' . implode('&', $query); } } else if (get_class($tableName) == 'Microsoft_WindowsAzure_Storage_TableEntityQuery') { // Option 2: $tableName is a Microsoft_WindowsAzure_Storage_TableEntityQuery instance
// Build queryString $queryString = $tableName->assembleQueryString(true);
// Change $tableName $tableName = $tableName->assembleFrom(true); } else { throw new Microsoft_WindowsAzure_Exception('Invalid argument: $tableName'); }
// Add continuation querystring parameters? if (!is_null($nextPartitionKey) && !is_null($nextRowKey)) { if ($queryString !== '') { $queryString .= '&'; }
$queryString .= '&NextPartitionKey=' . rawurlencode($nextPartitionKey) . '&NextRowKey=' . rawurlencode($nextRowKey); }
// Perform request $response = null; if ($this->isInBatch() && $this->getCurrentBatch()->getOperationCount() == 0) { $this->getCurrentBatch()->enlistOperation($tableName, $queryString, Microsoft_Http_Client::GET, array(), true, null); $response = $this->getCurrentBatch()->commit();
// Get inner response (multipart) $innerResponse = $response->getBody(); $innerResponse = substr($innerResponse, strpos($innerResponse, 'HTTP/1.1 200 OK')); $innerResponse = substr($innerResponse, 0, strpos($innerResponse, '--batchresponse')); $response = Microsoft_Http_Response::fromString($innerResponse); } else { $response = $this->_performRequest($tableName, $queryString, Microsoft_Http_Client::GET, array(), true, null); }
if ($response->isSuccessful()) { // Parse result $result = $this->_parseResponse($response); if (!$result) { return array(); }
$entries = null; if ($result->entry) { if (count($result->entry) > 1) { $entries = $result->entry; } else { $entries = array($result->entry); } } else { // This one is tricky... If we have properties defined, we have an entity. $properties = $result->xpath('//m:properties'); if ($properties) { $entries = array($result); } else { return array(); } }
// Create return value $returnValue = array(); foreach ($entries as $entry) { // Parse properties $properties = $entry->xpath('.//m:properties'); $properties = $properties[0]->children('http://schemas.microsoft.com/ado/2007/08/dataservices');
// Create entity $entity = new $entityClass('', ''); $entity->setAzureValues((array)$properties, $this->_throwExceptionOnMissingData);
// If we have a Microsoft_WindowsAzure_Storage_DynamicTableEntity, make sure all property types are OK if ($entity instanceof Microsoft_WindowsAzure_Storage_DynamicTableEntity) { foreach ($properties as $key => $value) { $attributes = $value->attributes('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); $type = (string)$attributes['type']; if ($type !== '') { $entity->setAzurePropertyType($key, $type); } } }
// Update etag $etag = $entry->attributes('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); $etag = (string)$etag['etag']; $entity->setEtag($etag);
// Add to result $returnValue[] = $entity; }
// More entities? if (!is_null($response->getHeader('x-ms-continuation-NextPartitionKey')) && !is_null($response->getHeader('x-ms-continuation-NextRowKey'))) { if (strpos($queryString, '$top') === false) { $returnValue = array_merge($returnValue, $this->retrieveEntities($tableName, $filter, $entityClass, $response->getHeader('x-ms-continuation-NextPartitionKey'), $response->getHeader('x-ms-continuation-NextRowKey'))); } }
// Return return $returnValue; } else { throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } }
/** * Update entity by replacing it * * @param string $tableName Table name * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to update * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) * @throws Microsoft_WindowsAzure_Exception */ public function updateEntity($tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false) { return $this->_changeEntity(Microsoft_Http_Client::PUT, $tableName, $entity, $verifyEtag); }
/** * Update entity by adding or updating properties * * @param string $tableName Table name * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to update * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) * @param array $properties Properties to merge. All properties will be used when omitted. * @throws Microsoft_WindowsAzure_Exception */ public function mergeEntity($tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false, $properties = array()) { $mergeEntity = null; if (is_array($properties) && count($properties) > 0) { // Build a new object $mergeEntity = new Microsoft_WindowsAzure_Storage_DynamicTableEntity($entity->getPartitionKey(), $entity->getRowKey());
// Keep only values mentioned in $properties $azureValues = $entity->getAzureValues(); foreach ($azureValues as $key => $value) { if (in_array($value->Name, $properties)) { $mergeEntity->setAzureProperty($value->Name, $value->Value, $value->Type); } } } else { $mergeEntity = $entity; }
// Ensure entity timestamp matches updated timestamp $entity->setTimestamp($this->isoDate());
return $this->_changeEntity(Microsoft_Http_Client::MERGE, $tableName, $mergeEntity, $verifyEtag); }
/** * Get error message from Microsoft_Http_Response * * @param Microsoft_Http_Response $response Repsonse * @param string $alternativeError Alternative error message * @return string */ protected function _getErrorMessage(Microsoft_Http_Response $response, $alternativeError = 'Unknown error.') { $response = $this->_parseResponse($response); if ($response && $response->message) { return (string)$response->message; } else { return $alternativeError; } }
/** * Update entity / merge entity * * @param string $httpVerb HTTP verb to use (PUT = update, MERGE = merge) * @param string $tableName Table name * @param Microsoft_WindowsAzure_Storage_TableEntity $entity Entity to update * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) * @throws Microsoft_WindowsAzure_Exception */ protected function _changeEntity($httpVerb = Microsoft_Http_Client::PUT, $tableName = '', Microsoft_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false) { if ($tableName === '') { throw new Microsoft_WindowsAzure_Exception('Table name is not specified.'); } if (is_null($entity)) { throw new Microsoft_WindowsAzure_Exception('Entity is not specified.'); }
// Add header information $headers = array(); $headers['Content-Type'] = 'application/atom+xml'; $headers['Content-Length'] = 0; if (!$verifyEtag) { $headers['If-Match'] = '*'; } else { $headers['If-Match'] = $entity->getEtag(); }
// Generate request body $requestBody = '<?xml version="1.0" encoding="utf-8" standalone="yes"?> <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"> <title /> <updated>{tpl:Updated}</updated> <author> <name /> </author> <id /> <content type="application/xml"> <m:properties> {tpl:Properties} </m:properties> </content> </entry>';
// Attempt to get timestamp from entity $timestamp = $entity->getTimestamp(); if ($timestamp == Microsoft_WindowsAzure_Storage_TableEntity::DEFAULT_TIMESTAMP) { $timestamp = $this->isoDate(); }
$requestBody = $this->_fillTemplate($requestBody, array( 'Updated' => $timestamp, 'Properties' => $this->_generateAzureRepresentation($entity) ));
// Add header information $headers = array(); $headers['Content-Type'] = 'application/atom+xml'; if (!$verifyEtag) { $headers['If-Match'] = '*'; } else { $headers['If-Match'] = $entity->getEtag(); }
// Perform request $response = null; if ($this->isInBatch()) { $this->getCurrentBatch()->enlistOperation($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', $httpVerb, $headers, true, $requestBody); return null; } else { $response = $this->_performRequest($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', $httpVerb, $headers, true, $requestBody); } if ($response->isSuccessful()) { // Update properties $entity->setEtag($response->getHeader('Etag')); $entity->setTimestamp($response->getHeader('Last-modified'));
return $entity; } else { throw new Microsoft_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); } }
/** * Generate RFC 1123 compliant date string * * @return string */ protected function _rfcDate() { return gmdate('D, d M Y H:i:s', time()) . ' GMT'; // RFC 1123 }
/** * Fill text template with variables from key/value array * * @param string $templateText Template text * @param array $variables Array containing key/value pairs * @return string */ protected function _fillTemplate($templateText, $variables = array()) { foreach ($variables as $key => $value) { $templateText = str_replace('{tpl:' . $key . '}', $value, $templateText); } return $templateText; }
/** * Generate Azure representation from entity (creates atompub markup from properties) * * @param Microsoft_WindowsAzure_Storage_TableEntity $entity * @return string */ protected function _generateAzureRepresentation(Microsoft_WindowsAzure_Storage_TableEntity $entity = null) { // Generate Azure representation from entity $azureRepresentation = array(); $azureValues = $entity->getAzureValues(); foreach ($azureValues as $azureValue) { $value = array(); $value[] = '<d:' . $azureValue->Name; if ($azureValue->Type != '') { $value[] = ' m:type="' . $azureValue->Type . '"'; } if (is_null($azureValue->Value)) { $value[] = ' m:null="true"'; } $value[] = '>';
if (!is_null($azureValue->Value)) { if (strtolower($azureValue->Type) == 'edm.boolean') { $value[] = ($azureValue->Value == true ? '1' : '0'); } else { $value[] = htmlspecialchars($azureValue->Value); } }
$value[] = '</d:' . $azureValue->Name . '>'; $azureRepresentation[] = implode('', $value); }
return implode('', $azureRepresentation); }
/** * Perform request using Microsoft_Http_Client channel * * @param string $path Path * @param string $queryString Query string * @param string $httpVerb HTTP verb the request will use * @param array $headers x-ms headers to add * @param boolean $forTableStorage Is the request for table storage? * @param mixed $rawData Optional RAW HTTP data to be sent over the wire * @param string $resourceType Resource type * @param string $requiredPermission Required permission * @return Microsoft_Http_Response */ protected function _performRequest( $path = '/', $queryString = '', $httpVerb = Microsoft_Http_Client::GET, $headers = array(), $forTableStorage = false, $rawData = null, $resourceType = Microsoft_WindowsAzure_Storage::RESOURCE_UNKNOWN, $requiredPermission = Microsoft_WindowsAzure_Credentials_CredentialsAbstract::PERMISSION_READ ) { // Add headers $headers['DataServiceVersion'] = '1.0;NetFx'; $headers['MaxDataServiceVersion'] = '1.0;NetFx';
// Perform request return parent::_performRequest( $path, $queryString, $httpVerb, $headers, $forTableStorage, $rawData, $resourceType, $requiredPermission ); } }
|