[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to [email protected] so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Service_WindowsAzure 17 * @subpackage Storage 18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 19 * @license http://framework.zend.com/license/new-bsd New BSD License 20 * @version $Id$ 21 */ 22 23 /** 24 * @see Zend_Service_WindowsAzure_Credentials_CredentialsAbstract 25 */ 26 require_once 'Zend/Service/WindowsAzure/Credentials/CredentialsAbstract.php'; 27 28 /** 29 * @see Zend_Service_WindowsAzure_Credentials_SharedKey 30 */ 31 require_once 'Zend/Service/WindowsAzure/Credentials/SharedKey.php'; 32 33 /** 34 * @see Zend_Service_WindowsAzure_Credentials_SharedKeyLite 35 */ 36 require_once 'Zend/Service/WindowsAzure/Credentials/SharedKeyLite.php'; 37 38 /** 39 * @see Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract 40 */ 41 require_once 'Zend/Service/WindowsAzure/RetryPolicy/RetryPolicyAbstract.php'; 42 43 /** 44 * @see Zend_Http_Client 45 */ 46 require_once 'Zend/Http/Client.php'; 47 48 /** 49 * @see Zend_Http_Response 50 */ 51 require_once 'Zend/Http/Response.php'; 52 53 /** 54 * @see Zend_Service_WindowsAzure_Storage 55 */ 56 require_once 'Zend/Service/WindowsAzure/Storage.php'; 57 58 /** 59 * @see Zend_Service_WindowsAzure_Storage_BatchStorageAbstract 60 */ 61 require_once 'Zend/Service/WindowsAzure/Storage/BatchStorageAbstract.php'; 62 63 /** 64 * @see Zend_Service_WindowsAzure_Storage_TableInstance 65 */ 66 require_once 'Zend/Service/WindowsAzure/Storage/TableInstance.php'; 67 68 /** 69 * @see Zend_Service_WindowsAzure_Storage_TableEntity 70 */ 71 require_once 'Zend/Service/WindowsAzure/Storage/TableEntity.php'; 72 73 /** 74 * @see Zend_Service_WindowsAzure_Storage_DynamicTableEntity 75 */ 76 require_once 'Zend/Service/WindowsAzure/Storage/DynamicTableEntity.php'; 77 78 /** 79 * @see Zend_Service_WindowsAzure_Storage_TableEntityQuery 80 */ 81 require_once 'Zend/Service/WindowsAzure/Storage/TableEntityQuery.php'; 82 83 /** 84 * @see Zend_Service_WindowsAzure_Exception 85 */ 86 require_once 'Zend/Service/WindowsAzure/Exception.php'; 87 88 89 /** 90 * @category Zend 91 * @package Zend_Service_WindowsAzure 92 * @subpackage Storage 93 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 94 * @license http://framework.zend.com/license/new-bsd New BSD License 95 */ 96 class Zend_Service_WindowsAzure_Storage_Table 97 extends Zend_Service_WindowsAzure_Storage_BatchStorageAbstract 98 { 99 /** 100 * Creates a new Zend_Service_WindowsAzure_Storage_Table instance 101 * 102 * @param string $host Storage host name 103 * @param string $accountName Account name for Windows Azure 104 * @param string $accountKey Account key for Windows Azure 105 * @param boolean $usePathStyleUri Use path-style URI's 106 * @param Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy Retry policy to use when making requests 107 */ 108 public function __construct($host = Zend_Service_WindowsAzure_Storage::URL_DEV_TABLE, $accountName = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_ACCOUNT, $accountKey = Zend_Service_WindowsAzure_Credentials_CredentialsAbstract::DEVSTORE_KEY, $usePathStyleUri = false, Zend_Service_WindowsAzure_RetryPolicy_RetryPolicyAbstract $retryPolicy = null) 109 { 110 parent::__construct($host, $accountName, $accountKey, $usePathStyleUri, $retryPolicy); 111 112 // Always use SharedKeyLite authentication 113 $this->_credentials = new Zend_Service_WindowsAzure_Credentials_SharedKeyLite($accountName, $accountKey, $this->_usePathStyleUri); 114 115 // API version 116 $this->_apiVersion = '2009-04-14'; 117 } 118 119 /** 120 * Check if a table exists 121 * 122 * @param string $tableName Table name 123 * @return boolean 124 */ 125 public function tableExists($tableName = '') 126 { 127 if ($tableName === '') { 128 throw new Zend_Service_WindowsAzure_Exception('Table name is not specified.'); 129 } 130 131 // List tables 132 $tables = $this->listTables($tableName); 133 foreach ($tables as $table) { 134 if ($table->Name == $tableName) { 135 return true; 136 } 137 } 138 139 return false; 140 } 141 142 /** 143 * List tables 144 * 145 * @param string $nextTableName Next table name, used for listing tables when total amount of tables is > 1000. 146 * @return array 147 * @throws Zend_Service_WindowsAzure_Exception 148 */ 149 public function listTables($nextTableName = '') 150 { 151 // Build query string 152 $queryString = ''; 153 if ($nextTableName != '') { 154 $queryString = '?NextTableName=' . $nextTableName; 155 } 156 157 // Perform request 158 $response = $this->_performRequest('Tables', $queryString, Zend_Http_Client::GET, null, true); 159 if ($response->isSuccessful()) { 160 // Parse result 161 $result = $this->_parseResponse($response); 162 163 if (!$result || !$result->entry) { 164 return array(); 165 } 166 167 $entries = null; 168 if (count($result->entry) > 1) { 169 $entries = $result->entry; 170 } else { 171 $entries = array($result->entry); 172 } 173 174 // Create return value 175 $returnValue = array(); 176 foreach ($entries as $entry) { 177 $tableName = $entry->xpath('.//m:properties/d:TableName'); 178 $tableName = (string)$tableName[0]; 179 180 $returnValue[] = new Zend_Service_WindowsAzure_Storage_TableInstance( 181 (string)$entry->id, 182 $tableName, 183 (string)$entry->link['href'], 184 (string)$entry->updated 185 ); 186 } 187 188 // More tables? 189 if (!is_null($response->getHeader('x-ms-continuation-NextTableName'))) { 190 $returnValue = array_merge($returnValue, $this->listTables($response->getHeader('x-ms-continuation-NextTableName'))); 191 } 192 193 return $returnValue; 194 } else { 195 throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); 196 } 197 } 198 199 /** 200 * Create table 201 * 202 * @param string $tableName Table name 203 * @return Zend_Service_WindowsAzure_Storage_TableInstance 204 * @throws Zend_Service_WindowsAzure_Exception 205 */ 206 public function createTable($tableName = '') 207 { 208 if ($tableName === '') { 209 throw new Zend_Service_WindowsAzure_Exception('Table name is not specified.'); 210 } 211 212 // Generate request body 213 $requestBody = '<?xml version="1.0" encoding="utf-8" standalone="yes"?> 214 <entry 215 xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 216 xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 217 xmlns="http://www.w3.org/2005/Atom"> 218 <title /> 219 <updated>{tpl:Updated}</updated> 220 <author> 221 <name /> 222 </author> 223 <id /> 224 <content type="application/xml"> 225 <m:properties> 226 <d:TableName>{tpl:TableName}</d:TableName> 227 </m:properties> 228 </content> 229 </entry>'; 230 231 $requestBody = $this->_fillTemplate($requestBody, array( 232 'BaseUrl' => $this->getBaseUrl(), 233 'TableName' => htmlspecialchars($tableName), 234 'Updated' => $this->isoDate(), 235 'AccountName' => $this->_accountName 236 )); 237 238 // Add header information 239 $headers = array(); 240 $headers['Content-Type'] = 'application/atom+xml'; 241 $headers['DataServiceVersion'] = '1.0;NetFx'; 242 $headers['MaxDataServiceVersion'] = '1.0;NetFx'; 243 244 // Perform request 245 $response = $this->_performRequest('Tables', '', Zend_Http_Client::POST, $headers, true, $requestBody); 246 if ($response->isSuccessful()) { 247 // Parse response 248 $entry = $this->_parseResponse($response); 249 250 $tableName = $entry->xpath('.//m:properties/d:TableName'); 251 $tableName = (string)$tableName[0]; 252 253 return new Zend_Service_WindowsAzure_Storage_TableInstance( 254 (string)$entry->id, 255 $tableName, 256 (string)$entry->link['href'], 257 (string)$entry->updated 258 ); 259 } else { 260 throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); 261 } 262 } 263 264 /** 265 * Delete table 266 * 267 * @param string $tableName Table name 268 * @throws Zend_Service_WindowsAzure_Exception 269 */ 270 public function deleteTable($tableName = '') 271 { 272 if ($tableName === '') { 273 throw new Zend_Service_WindowsAzure_Exception('Table name is not specified.'); 274 } 275 276 // Add header information 277 $headers = array(); 278 $headers['Content-Type'] = 'application/atom+xml'; 279 280 // Perform request 281 $response = $this->_performRequest('Tables(\'' . $tableName . '\')', '', Zend_Http_Client::DELETE, $headers, true, null); 282 if (!$response->isSuccessful()) { 283 throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); 284 } 285 } 286 287 /** 288 * Insert entity into table 289 * 290 * @param string $tableName Table name 291 * @param Zend_Service_WindowsAzure_Storage_TableEntity $entity Entity to insert 292 * @return Zend_Service_WindowsAzure_Storage_TableEntity 293 * @throws Zend_Service_WindowsAzure_Exception 294 */ 295 public function insertEntity($tableName = '', Zend_Service_WindowsAzure_Storage_TableEntity $entity = null) 296 { 297 if ($tableName === '') { 298 throw new Zend_Service_WindowsAzure_Exception('Table name is not specified.'); 299 } 300 if (is_null($entity)) { 301 throw new Zend_Service_WindowsAzure_Exception('Entity is not specified.'); 302 } 303 304 // Generate request body 305 $requestBody = '<?xml version="1.0" encoding="utf-8" standalone="yes"?> 306 <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"> 307 <title /> 308 <updated>{tpl:Updated}</updated> 309 <author> 310 <name /> 311 </author> 312 <id /> 313 <content type="application/xml"> 314 <m:properties> 315 {tpl:Properties} 316 </m:properties> 317 </content> 318 </entry>'; 319 320 $requestBody = $this->_fillTemplate($requestBody, array( 321 'Updated' => $this->isoDate(), 322 'Properties' => $this->_generateAzureRepresentation($entity) 323 )); 324 325 // Add header information 326 $headers = array(); 327 $headers['Content-Type'] = 'application/atom+xml'; 328 329 // Perform request 330 $response = null; 331 if ($this->isInBatch()) { 332 $this->getCurrentBatch()->enlistOperation($tableName, '', Zend_Http_Client::POST, $headers, true, $requestBody); 333 return null; 334 } else { 335 $response = $this->_performRequest($tableName, '', Zend_Http_Client::POST, $headers, true, $requestBody); 336 } 337 if ($response->isSuccessful()) { 338 // Parse result 339 $result = $this->_parseResponse($response); 340 341 $timestamp = $result->xpath('//m:properties/d:Timestamp'); 342 $timestamp = (string)$timestamp[0]; 343 344 $etag = $result->attributes('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); 345 $etag = (string)$etag['etag']; 346 347 // Update properties 348 $entity->setTimestamp($timestamp); 349 $entity->setEtag($etag); 350 351 return $entity; 352 } else { 353 throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); 354 } 355 } 356 357 /** 358 * Delete entity from table 359 * 360 * @param string $tableName Table name 361 * @param Zend_Service_WindowsAzure_Storage_TableEntity $entity Entity to delete 362 * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) 363 * @throws Zend_Service_WindowsAzure_Exception 364 */ 365 public function deleteEntity($tableName = '', Zend_Service_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false) 366 { 367 if ($tableName === '') { 368 throw new Zend_Service_WindowsAzure_Exception('Table name is not specified.'); 369 } 370 if (is_null($entity)) { 371 throw new Zend_Service_WindowsAzure_Exception('Entity is not specified.'); 372 } 373 374 // Add header information 375 $headers = array(); 376 if (!$this->isInBatch()) { 377 // http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/9e255447-4dc7-458a-99d3-bdc04bdc5474/ 378 $headers['Content-Type'] = 'application/atom+xml'; 379 } 380 $headers['Content-Length'] = 0; 381 if (!$verifyEtag) { 382 $headers['If-Match'] = '*'; 383 } else { 384 $headers['If-Match'] = $entity->getEtag(); 385 } 386 387 // Perform request 388 $response = null; 389 if ($this->isInBatch()) { 390 $this->getCurrentBatch()->enlistOperation($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', Zend_Http_Client::DELETE, $headers, true, null); 391 return null; 392 } else { 393 $response = $this->_performRequest($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', Zend_Http_Client::DELETE, $headers, true, null); 394 } 395 if (!$response->isSuccessful()) { 396 throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); 397 } 398 } 399 400 /** 401 * Retrieve entity from table, by id 402 * 403 * @param string $tableName Table name 404 * @param string $partitionKey Partition key 405 * @param string $rowKey Row key 406 * @param string $entityClass Entity class name* 407 * @return Zend_Service_WindowsAzure_Storage_TableEntity 408 * @throws Zend_Service_WindowsAzure_Exception 409 */ 410 public function retrieveEntityById($tableName = '', $partitionKey = '', $rowKey = '', $entityClass = 'Zend_Service_WindowsAzure_Storage_DynamicTableEntity') 411 { 412 if ($tableName === '') { 413 throw new Zend_Service_WindowsAzure_Exception('Table name is not specified.'); 414 } 415 if ($partitionKey === '') { 416 throw new Zend_Service_WindowsAzure_Exception('Partition key is not specified.'); 417 } 418 if ($rowKey === '') { 419 throw new Zend_Service_WindowsAzure_Exception('Row key is not specified.'); 420 } 421 if ($entityClass === '') { 422 throw new Zend_Service_WindowsAzure_Exception('Entity class is not specified.'); 423 } 424 425 426 // Check for combined size of partition key and row key 427 // http://msdn.microsoft.com/en-us/library/dd179421.aspx 428 if (strlen($partitionKey . $rowKey) >= 256) { 429 // Start a batch if possible 430 if ($this->isInBatch()) { 431 throw new Zend_Service_WindowsAzure_Exception('Entity cannot be retrieved. A transaction is required to retrieve the entity, but another transaction is already active.'); 432 } 433 434 $this->startBatch(); 435 } 436 437 // Fetch entities from Azure 438 $result = $this->retrieveEntities( 439 $this->select() 440 ->from($tableName) 441 ->wherePartitionKey($partitionKey) 442 ->whereRowKey($rowKey), 443 '', 444 $entityClass 445 ); 446 447 // Return 448 if (count($result) == 1) { 449 return $result[0]; 450 } 451 452 return null; 453 } 454 455 /** 456 * Create a new Zend_Service_WindowsAzure_Storage_TableEntityQuery 457 * 458 * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery 459 */ 460 public function select() 461 { 462 return new Zend_Service_WindowsAzure_Storage_TableEntityQuery(); 463 } 464 465 /** 466 * Retrieve entities from table 467 * 468 * @param string $tableName|Zend_Service_WindowsAzure_Storage_TableEntityQuery Table name -or- Zend_Service_WindowsAzure_Storage_TableEntityQuery instance 469 * @param string $filter Filter condition (not applied when $tableName is a Zend_Service_WindowsAzure_Storage_TableEntityQuery instance) 470 * @param string $entityClass Entity class name 471 * @param string $nextPartitionKey Next partition key, used for listing entities when total amount of entities is > 1000. 472 * @param string $nextRowKey Next row key, used for listing entities when total amount of entities is > 1000. 473 * @return array Array of Zend_Service_WindowsAzure_Storage_TableEntity 474 * @throws Zend_Service_WindowsAzure_Exception 475 */ 476 public function retrieveEntities($tableName = '', $filter = '', $entityClass = 'Zend_Service_WindowsAzure_Storage_DynamicTableEntity', $nextPartitionKey = null, $nextRowKey = null) 477 { 478 if ($tableName === '') { 479 throw new Zend_Service_WindowsAzure_Exception('Table name is not specified.'); 480 } 481 if ($entityClass === '') { 482 throw new Zend_Service_WindowsAzure_Exception('Entity class is not specified.'); 483 } 484 485 // Convenience... 486 if (class_exists($filter)) { 487 $entityClass = $filter; 488 $filter = ''; 489 } 490 491 // Query string 492 $queryString = ''; 493 494 // Determine query 495 if (is_string($tableName)) { 496 // Option 1: $tableName is a string 497 498 // Append parentheses 499 $tableName .= '()'; 500 501 // Build query 502 $query = array(); 503 504 // Filter? 505 if ($filter !== '') { 506 $query[] = '$filter=' . rawurlencode($filter); 507 } 508 509 // Build queryString 510 if (count($query) > 0) { 511 $queryString = '?' . implode('&', $query); 512 } 513 } else if (get_class($tableName) == 'Zend_Service_WindowsAzure_Storage_TableEntityQuery') { 514 // Option 2: $tableName is a Zend_Service_WindowsAzure_Storage_TableEntityQuery instance 515 516 // Build queryString 517 $queryString = $tableName->assembleQueryString(true); 518 519 // Change $tableName 520 $tableName = $tableName->assembleFrom(true); 521 } else { 522 throw new Zend_Service_WindowsAzure_Exception('Invalid argument: $tableName'); 523 } 524 525 // Add continuation querystring parameters? 526 if (!is_null($nextPartitionKey) && !is_null($nextRowKey)) { 527 if ($queryString !== '') { 528 $queryString .= '&'; 529 } 530 531 $queryString .= '&NextPartitionKey=' . rawurlencode($nextPartitionKey) . '&NextRowKey=' . rawurlencode($nextRowKey); 532 } 533 534 // Perform request 535 $response = null; 536 if ($this->isInBatch() && $this->getCurrentBatch()->getOperationCount() == 0) { 537 $this->getCurrentBatch()->enlistOperation($tableName, $queryString, Zend_Http_Client::GET, array(), true, null); 538 $response = $this->getCurrentBatch()->commit(); 539 540 // Get inner response (multipart) 541 $innerResponse = $response->getBody(); 542 $innerResponse = substr($innerResponse, strpos($innerResponse, 'HTTP/1.1 200 OK')); 543 $innerResponse = substr($innerResponse, 0, strpos($innerResponse, '--batchresponse')); 544 $response = Zend_Http_Response::fromString($innerResponse); 545 } else { 546 $response = $this->_performRequest($tableName, $queryString, Zend_Http_Client::GET, array(), true, null); 547 } 548 549 if ($response->isSuccessful()) { 550 // Parse result 551 $result = $this->_parseResponse($response); 552 if (!$result) { 553 return array(); 554 } 555 556 $entries = null; 557 if ($result->entry) { 558 if (count($result->entry) > 1) { 559 $entries = $result->entry; 560 } else { 561 $entries = array($result->entry); 562 } 563 } else { 564 // This one is tricky... If we have properties defined, we have an entity. 565 $properties = $result->xpath('//m:properties'); 566 if ($properties) { 567 $entries = array($result); 568 } else { 569 return array(); 570 } 571 } 572 573 // Create return value 574 $returnValue = array(); 575 foreach ($entries as $entry) { 576 // Parse properties 577 $properties = $entry->xpath('.//m:properties'); 578 $properties = $properties[0]->children('http://schemas.microsoft.com/ado/2007/08/dataservices'); 579 580 // Create entity 581 $entity = new $entityClass('', ''); 582 $entity->setAzureValues((array)$properties, true); 583 584 // If we have a Zend_Service_WindowsAzure_Storage_DynamicTableEntity, make sure all property types are OK 585 if ($entity instanceof Zend_Service_WindowsAzure_Storage_DynamicTableEntity) { 586 foreach ($properties as $key => $value) { 587 $attributes = $value->attributes('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); 588 $type = (string)$attributes['type']; 589 if ($type !== '') { 590 $entity->setAzurePropertyType($key, $type); 591 } 592 } 593 } 594 595 // Update etag 596 $etag = $entry->attributes('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); 597 $etag = (string)$etag['etag']; 598 $entity->setEtag($etag); 599 600 // Add to result 601 $returnValue[] = $entity; 602 } 603 604 // More entities? 605 if (!is_null($response->getHeader('x-ms-continuation-NextPartitionKey')) && !is_null($response->getHeader('x-ms-continuation-NextRowKey'))) { 606 if (strpos($queryString, '$top') === false) { 607 $returnValue = array_merge($returnValue, $this->retrieveEntities($tableName, $filter, $entityClass, $response->getHeader('x-ms-continuation-NextPartitionKey'), $response->getHeader('x-ms-continuation-NextRowKey'))); 608 } 609 } 610 611 // Return 612 return $returnValue; 613 } else { 614 throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); 615 } 616 } 617 618 /** 619 * Update entity by replacing it 620 * 621 * @param string $tableName Table name 622 * @param Zend_Service_WindowsAzure_Storage_TableEntity $entity Entity to update 623 * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) 624 * @throws Zend_Service_WindowsAzure_Exception 625 */ 626 public function updateEntity($tableName = '', Zend_Service_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false) 627 { 628 return $this->_changeEntity(Zend_Http_Client::PUT, $tableName, $entity, $verifyEtag); 629 } 630 631 /** 632 * Update entity by adding or updating properties 633 * 634 * @param string $tableName Table name 635 * @param Zend_Service_WindowsAzure_Storage_TableEntity $entity Entity to update 636 * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) 637 * @param array $properties Properties to merge. All properties will be used when omitted. 638 * @throws Zend_Service_WindowsAzure_Exception 639 */ 640 public function mergeEntity($tableName = '', Zend_Service_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false, $properties = array()) 641 { 642 $mergeEntity = null; 643 if (is_array($properties) && count($properties) > 0) { 644 // Build a new object 645 $mergeEntity = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($entity->getPartitionKey(), $entity->getRowKey()); 646 647 // Keep only values mentioned in $properties 648 $azureValues = $entity->getAzureValues(); 649 foreach ($azureValues as $key => $value) { 650 if (in_array($value->Name, $properties)) { 651 $mergeEntity->setAzureProperty($value->Name, $value->Value, $value->Type); 652 } 653 } 654 } else { 655 $mergeEntity = $entity; 656 } 657 658 return $this->_changeEntity(Zend_Http_Client::MERGE, $tableName, $mergeEntity, $verifyEtag); 659 } 660 661 /** 662 * Get error message from Zend_Http_Response 663 * 664 * @param Zend_Http_Response $response Repsonse 665 * @param string $alternativeError Alternative error message 666 * @return string 667 */ 668 protected function _getErrorMessage(Zend_Http_Response $response, $alternativeError = 'Unknown error.') 669 { 670 $response = $this->_parseResponse($response); 671 if ($response && $response->message) { 672 return (string)$response->message; 673 } else { 674 return $alternativeError; 675 } 676 } 677 678 /** 679 * Update entity / merge entity 680 * 681 * @param string $httpVerb HTTP verb to use (PUT = update, MERGE = merge) 682 * @param string $tableName Table name 683 * @param Zend_Service_WindowsAzure_Storage_TableEntity $entity Entity to update 684 * @param boolean $verifyEtag Verify etag of the entity (used for concurrency) 685 * @throws Zend_Service_WindowsAzure_Exception 686 */ 687 protected function _changeEntity($httpVerb = Zend_Http_Client::PUT, $tableName = '', Zend_Service_WindowsAzure_Storage_TableEntity $entity = null, $verifyEtag = false) 688 { 689 if ($tableName === '') { 690 throw new Zend_Service_WindowsAzure_Exception('Table name is not specified.'); 691 } 692 if (is_null($entity)) { 693 throw new Zend_Service_WindowsAzure_Exception('Entity is not specified.'); 694 } 695 696 // Add header information 697 $headers = array(); 698 $headers['Content-Type'] = 'application/atom+xml'; 699 $headers['Content-Length'] = 0; 700 if (!$verifyEtag) { 701 $headers['If-Match'] = '*'; 702 } else { 703 $headers['If-Match'] = $entity->getEtag(); 704 } 705 706 // Generate request body 707 $requestBody = '<?xml version="1.0" encoding="utf-8" standalone="yes"?> 708 <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"> 709 <title /> 710 <updated>{tpl:Updated}</updated> 711 <author> 712 <name /> 713 </author> 714 <id /> 715 <content type="application/xml"> 716 <m:properties> 717 {tpl:Properties} 718 </m:properties> 719 </content> 720 </entry>'; 721 722 $requestBody = $this->_fillTemplate($requestBody, array( 723 'Updated' => $this->isoDate(), 724 'Properties' => $this->_generateAzureRepresentation($entity) 725 )); 726 727 // Add header information 728 $headers = array(); 729 $headers['Content-Type'] = 'application/atom+xml'; 730 if (!$verifyEtag) { 731 $headers['If-Match'] = '*'; 732 } else { 733 $headers['If-Match'] = $entity->getEtag(); 734 } 735 736 // Perform request 737 $response = null; 738 if ($this->isInBatch()) { 739 $this->getCurrentBatch()->enlistOperation($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', $httpVerb, $headers, true, $requestBody); 740 return null; 741 } else { 742 $response = $this->_performRequest($tableName . '(PartitionKey=\'' . $entity->getPartitionKey() . '\', RowKey=\'' . $entity->getRowKey() . '\')', '', $httpVerb, $headers, true, $requestBody); 743 } 744 if ($response->isSuccessful()) { 745 // Update properties 746 $entity->setEtag($response->getHeader('Etag')); 747 $entity->setTimestamp($response->getHeader('Last-modified')); 748 749 return $entity; 750 } else { 751 throw new Zend_Service_WindowsAzure_Exception($this->_getErrorMessage($response, 'Resource could not be accessed.')); 752 } 753 } 754 755 /** 756 * Generate RFC 1123 compliant date string 757 * 758 * @return string 759 */ 760 protected function _rfcDate() 761 { 762 return gmdate('D, d M Y H:i:s', time()) . ' GMT'; // RFC 1123 763 } 764 765 /** 766 * Fill text template with variables from key/value array 767 * 768 * @param string $templateText Template text 769 * @param array $variables Array containing key/value pairs 770 * @return string 771 */ 772 protected function _fillTemplate($templateText, $variables = array()) 773 { 774 foreach ($variables as $key => $value) { 775 $templateText = str_replace('{tpl:' . $key . '}', $value, $templateText); 776 } 777 return $templateText; 778 } 779 780 /** 781 * Generate Azure representation from entity (creates atompub markup from properties) 782 * 783 * @param Zend_Service_WindowsAzure_Storage_TableEntity $entity 784 * @return string 785 */ 786 protected function _generateAzureRepresentation(Zend_Service_WindowsAzure_Storage_TableEntity $entity = null) 787 { 788 // Generate Azure representation from entity 789 $azureRepresentation = array(); 790 $azureValues = $entity->getAzureValues(); 791 foreach ($azureValues as $azureValue) { 792 $value = array(); 793 $value[] = '<d:' . $azureValue->Name; 794 if ($azureValue->Type != '') { 795 $value[] = ' m:type="' . $azureValue->Type . '"'; 796 } 797 if (is_null($azureValue->Value)) { 798 $value[] = ' m:null="true"'; 799 } 800 $value[] = '>'; 801 802 if (!is_null($azureValue->Value)) { 803 if (strtolower($azureValue->Type) == 'edm.boolean') { 804 $value[] = ($azureValue->Value == true ? '1' : '0'); 805 } else { 806 $value[] = htmlspecialchars($azureValue->Value); 807 } 808 } 809 810 $value[] = '</d:' . $azureValue->Name . '>'; 811 $azureRepresentation[] = implode('', $value); 812 } 813 814 return implode('', $azureRepresentation); 815 } 816 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |