Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Refactored Storage interface while implementing WindowsAzureTable#ins…

…ert() and WindowsAzureTable#update().
  • Loading branch information...
commit 6dbed9ce7089f37cd95bf644cec9176553e6f0e9 1 parent feef6cb
Benjamin Eberlei authored March 26, 2012
2  lib/Doctrine/KeyValueStore/Http/StreamClient.php
@@ -17,7 +17,7 @@
17 17
  * <http://www.doctrine-project.org>.
18 18
  */
19 19
 
20  
-namespace Doctrine\CouchDB\HTTP;
  20
+namespace Doctrine\KeyValueStore\Http;
21 21
 
22 22
 /**
23 23
  * Connection handler using PHPs stream wrappers.
8  lib/Doctrine/KeyValueStore/Storage/DBALStorage.php
@@ -73,7 +73,7 @@ public function requiresCompositePrimaryKeys()
73 73
      * @param array $data
74 74
      * @return void
75 75
      */
76  
-    function insert($key, array $data)
  76
+    function insert($className, $key, array $data)
77 77
     {
78 78
         try {
79 79
             $this->conn->insert($this->table, array(
@@ -91,7 +91,7 @@ function insert($key, array $data)
91 91
      * @param array $data
92 92
      * @return void
93 93
      */
94  
-    public function update($key, array $data)
  94
+    public function update($className, $key, array $data)
95 95
     {
96 96
         try {
97 97
             $this->conn->update($this->table, array(
@@ -109,7 +109,7 @@ public function update($key, array $data)
109 109
      * @param array|string $key
110 110
      * @return void
111 111
      */
112  
-    public function delete($key)
  112
+    public function delete($className, $key)
113 113
     {
114 114
         try {
115 115
             $this->conn->delete($this->table, array($this->keyColumn => $key));
@@ -123,7 +123,7 @@ public function delete($key)
123 123
      * @param array|string $key
124 124
      * @return array
125 125
      */
126  
-    public function find($key)
  126
+    public function find($className, $key)
127 127
     {
128 128
         $sql = "SELECT " . $this->dataColumn . " FROM " . $this->table . " " .
129 129
                $this->keyColumn = " = ?";
10  lib/Doctrine/KeyValueStore/Storage/DoctrineCacheStorage.php
@@ -73,25 +73,27 @@ private function flattenKey($key)
73 73
         return $hash;
74 74
     }
75 75
 
76  
-    public function insert($key, array $data)
  76
+    public function insert($className, $key, array $data)
77 77
     {
78 78
         $key = $this->flattenKey($key);
  79
+        $data['php_class'] = $className;
79 80
         $this->cache->save($key, $data);
80 81
     }
81 82
 
82  
-    public function update($key, array $data)
  83
+    public function update($className, $key, array $data)
83 84
     {
84 85
         $key = $this->flattenKey($key);
  86
+        $data['php_class'] = $className;
85 87
         $this->cache->save($key, $data);
86 88
     }
87 89
 
88  
-    public function delete($key)
  90
+    public function delete($className, $key)
89 91
     {
90 92
         $key = $this->flattenKey($key);
91 93
         $this->cache->delete($key);
92 94
     }
93 95
 
94  
-    public function find($key)
  96
+    public function find($className, $key)
95 97
     {
96 98
         $key = $this->flattenKey($key);
97 99
         return $this->cache->fetch($key);
12  lib/Doctrine/KeyValueStore/Storage/Storage.php
@@ -66,36 +66,40 @@ function requiresCompositePrimaryKeys();
66 66
     /**
67 67
      * Insert data into the storage key specified.
68 68
      *
  69
+     * @param string $className
69 70
      * @param array|string $key
70 71
      * @param array $data
71 72
      * @return void
72 73
      */
73  
-    function insert($key, array $data);
  74
+    function insert($className, $key, array $data);
74 75
 
75 76
     /**
76 77
      * Update data into the given key.
77 78
      *
  79
+     * @param string $className
78 80
      * @param array|string $key
79 81
      * @param array $data
80 82
      * @return void
81 83
      */
82  
-    function update($key, array $data);
  84
+    function update($className, $key, array $data);
83 85
 
84 86
     /**
85 87
      * Delete data at key
86 88
      *
  89
+     * @param string $className
87 90
      * @param array|string $key
88 91
      * @return void
89 92
      */
90  
-    function delete($key);
  93
+    function delete($className, $key);
91 94
 
92 95
     /**
93 96
      * Find data at key
94 97
      *
  98
+     * @param string $className
95 99
      * @param array|string $key
96 100
      * @return array
97 101
      */
98  
-    function find($key);
  102
+    function find($className, $key);
99 103
 
100 104
     /**
101 105
      * Return a name of the underlying storage.
33  lib/Doctrine/KeyValueStore/Storage/WindowsAzureTable/SharedKeyAuthorization.php
... ...
@@ -0,0 +1,33 @@
  1
+<?php
  2
+/*
  3
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14
+ *
  15
+ * This software consists of voluntary contributions made by many individuals
  16
+ * and is licensed under the LGPL. For more information, see
  17
+ * <http://www.doctrine-project.org>.
  18
+ */
  19
+
  20
+namespace Doctrine\KeyValueStore\Storage\WindowsAzureTable;
  21
+
  22
+class SharedKeyAuthorization implements AuthorizationSchema
  23
+{
  24
+    /**
  25
+     * @override
  26
+     * {@inheritDocs}
  27
+     */
  28
+    public function signRequest($method, $body, array $headers)
  29
+    {
  30
+        return "";
  31
+    }
  32
+}
  33
+
181  lib/Doctrine/KeyValueStore/Storage/WindowsAzureTableStorage.php
@@ -19,7 +19,8 @@
19 19
 
20 20
 namespace Doctrine\KeyValueStore\Storage;
21 21
 
22  
-use Doctrine\KeyValueStore\HTTP\HttpClient;
  22
+use Doctrine\KeyValueStore\Http\Client;
  23
+use Doctrine\KeyValueStore\Storage\WindowsAzureTable\AuthorizationSchema;
23 24
 
24 25
 /**
25 26
  * Storage implementation for Microsoft Windows Azure Table.
@@ -31,8 +32,36 @@
31 32
 class WindowsAzureTableStorage implements Storage
32 33
 {
33 34
     const WINDOWS_AZURE_TABLE_BASEURL = 'https://%s.table.core.windows.net';
  35
+
  36
+    const METADATA_NS = 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata';
  37
+    const DATA_NS = 'http://schemas.microsoft.com/ado/2007/08/dataservices';
  38
+
  39
+    /**
  40
+     * @var string
  41
+     */
  42
+    const XML_TEMPLATE_ENTITY = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>
  43
+<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">
  44
+  <title />
  45
+  <updated></updated>
  46
+  <author>
  47
+    <name />
  48
+  </author>
  49
+  <id />
  50
+  <content type="application/xml">
  51
+    <m:properties>
  52
+    </m:properties>
  53
+  </content>
  54
+</entry>';
  55
+
  56
+    const TYPE_INT32 = 'Edm.Int32';
  57
+    const TYPE_INT64 = 'Edm.Int64';
  58
+    const TYPE_DATETIME = 'Edm.DateTime';
  59
+    const TYPE_BOOLEAN = 'Edm.Boolean';
  60
+    const TYPE_DOUBLE = 'Edm.Double';
  61
+    const TYPE_BINARY = 'Edm.Binary';
  62
+
34 63
     /**
35  
-     * @var \Doctrine\KeyValueStore\HTTP\HttpClient
  64
+     * @var \Doctrine\KeyValueStore\Http\Client
36 65
      */
37 66
     private $client;
38 67
 
@@ -47,14 +76,21 @@ class WindowsAzureTableStorage implements Storage
47 76
     private $baseUrl;
48 77
 
49 78
     /**
  79
+     * @var DateTime
  80
+     */
  81
+    private $now;
  82
+
  83
+    /**
50 84
      * @param HttpClient $client
51 85
      * @param AuthorizationSchema $authorization
52 86
      */
53  
-    public function __construct(HttpClient $client, $accountName, AuthorizationSchema $authorization)
  87
+    public function __construct(Client $client, $accountName, AuthorizationSchema $authorization, \DateTime $now)
54 88
     {
55 89
         $this->client = $client;
56 90
         $this->authorization = $authorization;
57 91
         $this->baseUrl = sprintf(self::WINDOWS_AZURE_TABLE_BASEURL, $accountName);
  92
+        $this->now = $now ? clone $now : new \DateTime();
  93
+        $this->now->setTimeZone(new \DateTimeZone("UTC"));
58 94
     }
59 95
 
60 96
     public function supportsPartialUpdates()
@@ -72,21 +108,152 @@ public function requiresCompositePrimaryKeys()
72 108
         return true;
73 109
     }
74 110
 
75  
-    public function insert($key, array $data)
  111
+    private function now()
  112
+    {
  113
+        return $this->isoDate($this->now);
  114
+    }
  115
+    
  116
+    private function isoDate(\DateTime $date)
  117
+    {
  118
+        return str_replace('+00:00', '.0000000Z', $date->format('c'));
  119
+    }
  120
+
  121
+    private function createDomDocumentRequestBody()
  122
+    {
  123
+        $dom = new \DOMDocument('1.0', 'UTF-8');
  124
+        $dom->loadXML(self::XML_TEMPLATE_ENTITY);
  125
+
  126
+        $updatedNodes = $dom->getElementsByTagName('updated');
  127
+        $updatedNodes->item(0)->appendChild($dom->createTextNode($this->now()));
  128
+
  129
+        return $dom;
  130
+    }
  131
+
  132
+    public function insert($className, $key, array $data)
  133
+    {
  134
+        $headers = array(
  135
+            'Content-Type' => 'application/atom+xml',
  136
+            'x-ms-date' => $this->now(),
  137
+        );
  138
+        // TODO: This sucks
  139
+        $tableName = $className;
  140
+
  141
+        $dom = $this->createDomDocumentRequestBody();
  142
+
  143
+        $propertiesNode = $dom->getElementsByTagNameNS(self::METADATA_NS, 'properties')->item(0);
  144
+
  145
+        $this->serializeKeys($propertiesNode, $key);
  146
+        $this->serializeProperties($propertiesNode, $data);
  147
+
  148
+        $contentNodes = $dom->getElementsByTagName('content');
  149
+        $contentNodes->item(0)->appendChild($propertiesNode);
  150
+        $xml = $dom->saveXML();
  151
+
  152
+        $url = $this->baseUrl . '/' . $tableName;
  153
+        $this->request('POST', $url, $xml, $headers);
  154
+    }
  155
+
  156
+    private function serializeKeys($propertiesNode, $key)
76 157
     {
  158
+        $keys = 0;
  159
+        foreach ($key as $keyName => $keyValue) {
  160
+            switch ($keys) {
  161
+                case 0:
  162
+                    $partitionKey = $propertiesNode->ownerDocument->createElementNS(self::DATA_NS, 'PartitionKey', $keyValue);
  163
+                    $propertiesNode->appendChild($partitionKey);
  164
+                    break;
  165
+                case 1:
  166
+                    $rowKey = $propertiesNode->ownerDocument->createElementNS(self::DATA_NS, 'RowKey', $keyValue);
  167
+                    $propertiesNode->appendChild($rowKey);
  168
+                    break;
  169
+                default:
  170
+                    throw new \RuntimeException("Only exactly 2 composite key fields allowed.");
  171
+            }
  172
+            $keys++;
  173
+        }
  174
+    }
77 175
 
  176
+    private function request($method, $url, $xml, $headers)
  177
+    {
  178
+        $authorizationHeader = $this->authorization->signRequest($method, "", $headers);
  179
+        $authorizationParts = explode(":" , $authorizationHeader, 2);
  180
+        $headers['Content-Length'] = strlen($xml);
  181
+        $headers[$authorizationParts[0]] = ltrim($authorizationParts[1]);
  182
+        $response = $this->client->request($method, $url, $xml, $headers);
78 183
     }
79 184
 
80  
-    public function update($key, array $data)
  185
+    private function serializeProperties($propertiesNode, array $data)
81 186
     {
  187
+        foreach ($data as $propertyName => $propertyValue) {
  188
+            if ( isset($key[$propertyName])) {
  189
+                continue;
  190
+            }
  191
+
  192
+            $type = $this->getPropertyType($propertyValue);
  193
+            $propertyValue = $this->convertPropertyValue($propertyValue, $type);
  194
+
  195
+            $property = $propertiesNode->ownerDocument->createElementNS(self::DATA_NS, $propertyName, $propertyValue);
  196
+            if ($propertyValue === null) {
  197
+                $property->setAttributeNS(self::METDATA_NS, 'null', 'true');
  198
+            }
  199
+
  200
+            $propertiesNode->appendChild($property);
  201
+        }
  202
+    }
  203
+
  204
+    private function getPropertyType($propertyValue)
  205
+    {
  206
+        if ($propertyValue instanceof \DateTime) {
  207
+            return self::TYPE_DATETIME;
  208
+        }
  209
+        return null;
  210
+    }
  211
+
  212
+    private function convertPropertyValue($propertyValue, $type)
  213
+    {
  214
+        switch ($type) {
  215
+            case self::TYPE_DATETIME:
  216
+                $propertyValue = $this->isoDate($propertyValue);
  217
+                break;
  218
+        }
  219
+        return $propertyValue;
  220
+    }
  221
+
  222
+    public function update($className, $key, array $data)
  223
+    {
  224
+        $headers = array(
  225
+            'Content-Type' => 'application/atom+xml',
  226
+            'x-ms-date' => $this->now(),
  227
+            'If-Match' => '*',
  228
+        );
  229
+        // TODO: This sucks
  230
+        $tableName = $className;
  231
+
  232
+        $dom = $this->createDomDocumentRequestBody();
  233
+
  234
+        $propertiesNode = $dom->getElementsByTagNameNS(self::METADATA_NS, 'properties')->item(0);
  235
+
  236
+        $this->serializeKeys($propertiesNode, $key);
  237
+        $this->serializeProperties($propertiesNode, $data);
  238
+        $keys = array_values($key);
  239
+        $url = $this->baseUrl . '/' . $tableName ."(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')";
  240
+        $idNode = $dom->getElementsByTagName('id')->item(0);
  241
+        $idNode->appendChild($dom->createTextNode($url));
  242
+
  243
+        $contentNodes = $dom->getElementsByTagName('content');
  244
+        $contentNodes->item(0)->appendChild($propertiesNode);
  245
+        $xml = $dom->saveXML();
82 246
 
  247
+        $this->request('POST', $url, $xml, $headers);
83 248
     }
84 249
 
85  
-    public function delete($key)
  250
+    public function delete($className, $key)
86 251
     {
  252
+        $keys = array_values($key);
  253
+        $url = $this->baseUrl . '/' . $tableName ."(PartitionKey='" . $keys[0] . "', RowKey='" . $keys[1] . "')";
87 254
     }
88 255
 
89  
-    public function find($key)
  256
+    public function find($className, $key)
90 257
     {
91 258
 
92 259
     }
10  lib/Doctrine/KeyValueStore/UnitOfWork.php
@@ -52,7 +52,7 @@ public function reconsititute($className, $key)
52 52
     {
53 53
         $class = $this->cmf->getMetadataFor($className);
54 54
         $id = $this->idHandler->normalizeId($class, $key);
55  
-        $data = $this->storageDriver->find($id);
  55
+        $data = $this->storageDriver->find($className, $id);
56 56
 
57 57
         $object = $this->tryGetById($id);
58 58
         if ( ! $object) {
@@ -157,8 +157,7 @@ private function processIdentityMap()
157 157
             $changeSet = $this->computeChangeSet($this->cmf->getMetadataFor(get_class($object)), $object);
158 158
 
159 159
             if ($changeSet) {
160  
-                $changeSet['php_class'] = get_class($object);
161  
-                $this->storageDriver->update($this->identifiers[$hash], $changeSet);
  160
+                $this->storageDriver->update(get_class($object), $this->identifiers[$hash], $changeSet);
162 161
 
163 162
                 if ($this->storageDriver->supportsPartialUpdates()) {
164 163
                     $this->originalData[$hash] = array_merge($this->originalData[$hash], $changeSet);
@@ -180,12 +179,11 @@ private function processInsertions()
180 179
             }
181 180
 
182 181
             $data = $this->getObjectSnapshot($class, $object);
183  
-            $data['php_class'] = get_class($object);
184 182
 
185 183
             $oid = spl_object_hash($object);
186 184
             $idHash = $this->idHandler->hash($id);
187 185
 
188  
-            $this->storageDriver->insert($id, $data);
  186
+            $this->storageDriver->insert(get_class($object), $id, $data);
189 187
 
190 188
             $this->originalData[$oid] = $data;
191 189
             $this->identifiers[$oid] = $id;
@@ -200,7 +198,7 @@ private function processDeletions()
200 198
             $id = $this->identifiers[$oid];
201 199
             $idHash = $this->idHandler->hash($id);
202 200
 
203  
-            $this->storageDriver->delete($id);
  201
+            $this->storageDriver->delete(get_class($object), $id);
204 202
 
205 203
             unset($this->identifiers[$oid], $this->originalData[$oid], $this->identityMap[$idHash]);
206 204
         }
2  tests/Doctrine/Tests/KeyValueStore/Functional/SingleBasicCrudTest.php
@@ -32,7 +32,7 @@ public function populate($id, array $data)
32 32
 
33 33
     public function find($id)
34 34
     {
35  
-        return $this->storage->find($id);
  35
+        return $this->storage->find('', $id);
36 36
     }
37 37
 }
38 38
 
40  tests/Doctrine/Tests/KeyValueStore/Storage/AbstractStorageTestCase.php
@@ -18,19 +18,47 @@ public function setUp()
18 18
         $this->storage = $this->createStorage();
19 19
     }
20 20
 
21  
-    public function testInsertThenFindCompositeKey()
  21
+    public function testInsertCompositeKey()
22 22
     {
23  
-        if ( ! $this->storage->supportsCompositeKeys()) {
  23
+        if ( ! $this->storage->supportsCompositePrimaryKeys()) {
24 24
             $this->markTestSkipped("Composite keys need to be supported for this test to run.");
25 25
         }
26 26
 
27 27
         $key = array('dist' => 'foo', 'range' => 100);
28  
-        $data = array('dist' => 'foo', 'range' => 100, 'name' => 'Test', 'value' => 'val', 'date' => new \DateTime("2012-03-26 12:12:12"));
  28
+        $data = array(
  29
+            'dist' => 'foo',
  30
+            'range' => 100,
  31
+            'name' => 'Test',
  32
+            'value' => 1,
  33
+            'amount' => 200.23,
  34
+            'timestamp' => new \DateTime("2012-03-26 12:12:12")
  35
+        );
29 36
 
30  
-        $this->storage->insert($key, $data);
31  
-        $foundData = $this->storage->find($key);
  37
+        $this->mockInsertCompositeKey($key, $data);
  38
+        $this->storage->insert('stdClass', $key, $data);
  39
+    }
  40
+
  41
+    public function testUpdateCompositeKey()
  42
+    {
  43
+        if ( ! $this->storage->supportsCompositePrimaryKeys()) {
  44
+            $this->markTestSkipped("Composite keys need to be supported for this test to run.");
  45
+        }
  46
+
  47
+        $key = array('dist' => 'foo', 'range' => 100);
  48
+        $data = array(
  49
+            'dist' => 'foo',
  50
+            'range' => 100,
  51
+            'name' => 'Test',
  52
+            'value' => 1,
  53
+            'amount' => 200.23,
  54
+            'timestamp' => new \DateTime("2012-03-26 12:12:12")
  55
+        );
32 56
 
33  
-        $this->assertEquals($data, $foundData);
  57
+        $this->mockUpdateCompositeKey($key, $data);
  58
+        $this->storage->update('stdClass', $key, $data);
34 59
     }
  60
+
  61
+    abstract function mockInsertCompositeKey($key, $data);
  62
+    abstract function mockUpdateCompositeKey($key, $data);
35 63
 }
36 64
 
126  tests/Doctrine/Tests/KeyValueStore/Storage/WindowsAzureTableStorageTest.php
@@ -2,30 +2,126 @@
2 2
 
3 3
 namespace Doctrine\Tests\KeyValueStore\Storage;
4 4
 
  5
+use Doctrine\KeyValueStore\Storage\WindowsAzureTable\SharedKeyAuthorization;
  6
+use Doctrine\KeyValueStore\Storage\WindowsAzureTableStorage;
  7
+use Doctrine\KeyValueStore\Http\StreamClient;
  8
+use Doctrine\KeyValueStore\Http\Response;
  9
+
5 10
 class WindowsAzureTableStorageTest extends AbstractStorageTestCase
6 11
 {
  12
+    private $client;
  13
+
7 14
     protected function createStorage()
8 15
     {
9  
-        if ( empty($GLOBALS['DOCTRINE_KEYVALUE_AZURE_NAME']) || empty($GLOBALS['DOCTRINE_KEYVALUE_AZURE_KEY'])) {
10  
-            $this->markTestSkipped("No Azure information provided.");
11  
-        }
12  
-
13  
-        switch ($GLOBALS['DOCTRINE_KEYVALUE_AZURE_AUTHSCHEMA']) {
14  
-            case 'shared':
15  
-                $auth = new SharedKeyAuthorization();
16  
-                break;
17  
-            case 'sharedlite':
18  
-                $auth = new SharedKeyLiteAuthorization();
19  
-                break;
20  
-            default:
21  
-                $this->markTestSkipped("Unknown auth schema " . $GLOBALS['DOCTRINE_KEYVALUE_AZURE_AUTHSCHEMA']);
22  
-        }
  16
+        $this->client = $this->getMock('Doctrine\KeyValueStore\Http\Client');
  17
+        $auth = $this->getMock('Doctrine\KeyValueStore\Storage\WindowsAzureTable\AuthorizationSchema');
  18
+        $auth->expects($this->any())->method('signRequest')->will($this->returnValue('Authorization: SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM='));
23 19
 
24 20
         $storage = new WindowsAzureTableStorage(
25  
-            $client, $GLOBALS['DOCTRINE_KEYVALUE_AZURE_NAME'], $auth
  21
+            $this->client, 'teststore', $auth, new \DateTime('2012-03-26 10:10:10', new \DateTimeZone('UTC'))
26 22
         );
27 23
 
28 24
         return $storage;
29 25
     }
  26
+
  27
+    public function mockInsertCompositeKey($key, $data)
  28
+    {
  29
+        $expectedHeaders = array(
  30
+            'Content-Type' => 'application/atom+xml',
  31
+            'Content-Length' => 659,
  32
+            'x-ms-date' => '2012-03-26T10:10:10.0000000Z',
  33
+            'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
  34
+        );
  35
+
  36
+        $this->client->expects($this->at(0))
  37
+                     ->method('request')
  38
+                     ->with(
  39
+                        $this->equalTo('POST'),
  40
+                        $this->equalTo('https://teststore.table.core.windows.net/stdClass'),
  41
+                        $this->equalTo(<<<XML
  42
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
  43
+<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">
  44
+  <title/>
  45
+  <updated>2012-03-26T10:10:10.0000000Z</updated>
  46
+  <author>
  47
+    <name/>
  48
+  </author>
  49
+  <id/>
  50
+  <content type="application/xml">
  51
+    
  52
+  <m:properties>
  53
+    <d:PartitionKey>foo</d:PartitionKey><d:RowKey>100</d:RowKey><d:dist>foo</d:dist><d:range>100</d:range><d:name>Test</d:name><d:value>1</d:value><d:amount>200.23</d:amount><d:timestamp>2012-03-26T12:12:12+02:00</d:timestamp></m:properties></content>
  54
+</entry>
  55
+
  56
+XML
  57
+                        ),
  58
+                        $this->equalTo($expectedHeaders)
  59
+                     )->will($this->returnValue(
  60
+                        new Response(201, <<<XML
  61
+<?xml version="1.0" ?>
  62
+<entry xml:base="http://myaccount.table.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/&quot;datetime'2008-09-18T23%3A46%3A19.4277424Z'&quot;" xmlns="http://www.w3.org/2005/Atom">
  63
+  <id>http://myaccount.table.core.windows.net/mytable(PartitionKey='foo',RowKey='100')</id>
  64
+  <title type="text"></title>
  65
+  <updated>2008-09-18T23:46:19.3857256Z</updated>
  66
+  <author>
  67
+    <name />
  68
+  </author>
  69
+  <link rel="edit" title="stdClass" href="stdClass(PartitionKey='foo',RowKey='100')" />
  70
+  <category term="myaccount.Tables" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  71
+  <content type="application/xml">
  72
+    <m:properties>
  73
+      <d:PartitionKey>foo</d:PartitionKey>
  74
+      <d:RowKey>100</d:RowKey>
  75
+      <d:timestamp m:type="Edm.DateTime">2008-09-18T23:46:19.4277424Z</d:timestamp>
  76
+      <d:name>Test</d:name>
  77
+      <d:value m:type="Edm.Int32">23</d:value>
  78
+      <d:amount m:type="Edm.Double">200.23</d:amount>
  79
+    </m:properties>
  80
+  </content>
  81
+</entry>
  82
+XML
  83
+, array()
  84
+
  85
+                     ))
  86
+        );
  87
+    }
  88
+
  89
+    public function mockUpdateCompositeKey($key, $data)
  90
+    {
  91
+        $expectedHeaders = array(
  92
+            'Content-Type' => 'application/atom+xml',
  93
+            'Content-Length' => 746,
  94
+            'x-ms-date' => '2012-03-26T10:10:10.0000000Z',
  95
+            'If-Match' => '*',
  96
+            'Authorization' => 'SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=',
  97
+        );
  98
+
  99
+        $this->client->expects($this->at(0))
  100
+                     ->method('request')
  101
+                     ->with(
  102
+                        $this->equalTo('POST'),
  103
+                        $this->equalTo("https://teststore.table.core.windows.net/stdClass(PartitionKey='foo', RowKey='100')"),
  104
+                        $this->equalTo(<<<XML
  105
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
  106
+<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">
  107
+  <title/>
  108
+  <updated>2012-03-26T10:10:10.0000000Z</updated>
  109
+  <author>
  110
+    <name/>
  111
+  </author>
  112
+  <id>https://teststore.table.core.windows.net/stdClass(PartitionKey='foo', RowKey='100')</id>
  113
+  <content type="application/xml">
  114
+    
  115
+  <m:properties>
  116
+    <d:PartitionKey>foo</d:PartitionKey><d:RowKey>100</d:RowKey><d:dist>foo</d:dist><d:range>100</d:range><d:name>Test</d:name><d:value>1</d:value><d:amount>200.23</d:amount><d:timestamp>2012-03-26T12:12:12+02:00</d:timestamp></m:properties></content>
  117
+</entry>
  118
+
  119
+XML
  120
+                        ),
  121
+                        $this->equalTo($expectedHeaders))
  122
+                     ->will($this->returnValue(new Response(204, "", array()))
  123
+        );
  124
+
  125
+    }
30 126
 }
31 127
 

0 notes on commit 6dbed9c

Please sign in to comment.
Something went wrong with that request. Please try again.