TableRestProxy::updateEntity()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 3
dl 0
loc 6
rs 10
1
<?php
2
3
/**
4
 * LICENSE: The MIT License (the "License")
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 * https://github.com/azure/azure-storage-php/LICENSE
8
 *
9
 * Unless required by applicable law or agreed to in writing, software
10
 * distributed under the License is distributed on an "AS IS" BASIS,
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
 * See the License for the specific language governing permissions and
13
 * limitations under the License.
14
 *
15
 * PHP version 5
16
 *
17
 * @category  Microsoft
18
 * @package   MicrosoftAzure\Storage\Table
19
 * @author    Azure Storage PHP SDK <[email protected]>
20
 * @copyright 2016 Microsoft Corporation
21
 * @license   https://github.com/azure/azure-storage-php/LICENSE
22
 * @link      https://github.com/azure/azure-storage-php
23
 */
24
25
namespace MicrosoftAzure\Storage\Table;
26
27
use MicrosoftAzure\Storage\Common\Internal\ServiceRestTrait;
28
use MicrosoftAzure\Storage\Common\Internal\Resources;
29
use MicrosoftAzure\Storage\Common\Internal\Utilities;
30
use MicrosoftAzure\Storage\Common\Internal\Validate;
31
use MicrosoftAzure\Storage\Common\Internal\Http\HttpCallContext;
32
use MicrosoftAzure\Storage\Common\Internal\ServiceRestProxy;
33
use MicrosoftAzure\Storage\Common\LocationMode;
34
use MicrosoftAzure\Storage\Table\Internal\ITable;
35
use MicrosoftAzure\Storage\Table\Models\TableServiceOptions;
36
use MicrosoftAzure\Storage\Table\Models\EdmType;
37
use MicrosoftAzure\Storage\Table\Models\Filters;
38
use MicrosoftAzure\Storage\Table\Models\Entity;
39
use MicrosoftAzure\Storage\Table\Models\Query;
40
use MicrosoftAzure\Storage\Table\Models\Filters\Filter;
41
use MicrosoftAzure\Storage\Table\Models\Filters\PropertyNameFilter;
42
use MicrosoftAzure\Storage\Table\Models\Filters\ConstantFilter;
43
use MicrosoftAzure\Storage\Table\Models\Filters\UnaryFilter;
44
use MicrosoftAzure\Storage\Table\Models\Filters\BinaryFilter;
45
use MicrosoftAzure\Storage\Table\Models\Filters\QueryStringFilter;
46
use MicrosoftAzure\Storage\Table\Models\GetTableResult;
47
use MicrosoftAzure\Storage\Table\Models\GetTableOptions;
48
use MicrosoftAzure\Storage\Table\Models\GetEntityOptions;
49
use MicrosoftAzure\Storage\Table\Models\TableServiceCreateOptions;
50
use MicrosoftAzure\Storage\Table\Models\QueryTablesOptions;
51
use MicrosoftAzure\Storage\Table\Models\QueryTablesResult;
52
use MicrosoftAzure\Storage\Table\Models\InsertEntityResult;
53
use MicrosoftAzure\Storage\Table\Models\UpdateEntityResult;
54
use MicrosoftAzure\Storage\Table\Models\QueryEntitiesOptions;
55
use MicrosoftAzure\Storage\Table\Models\QueryEntitiesResult;
56
use MicrosoftAzure\Storage\Table\Models\DeleteEntityOptions;
57
use MicrosoftAzure\Storage\Table\Models\GetEntityResult;
58
use MicrosoftAzure\Storage\Table\Models\BatchOperationType;
59
use MicrosoftAzure\Storage\Table\Models\BatchOperationParameterName;
60
use MicrosoftAzure\Storage\Table\Models\BatchResult;
61
use MicrosoftAzure\Storage\Table\Models\TableACL;
62
use MicrosoftAzure\Storage\Common\Internal\Http\HttpFormatter;
63
use MicrosoftAzure\Storage\Table\Internal\IODataReaderWriter;
64
use MicrosoftAzure\Storage\Table\Internal\IMimeReaderWriter;
65
use MicrosoftAzure\Storage\Common\Internal\Serialization\ISerializer;
66
67
/**
68
 * This class constructs HTTP requests and receive HTTP responses for table
69
 * service layer.
70
 *
71
 * @category  Microsoft
72
 * @package   MicrosoftAzure\Storage\Table
73
 * @author    Azure Storage PHP SDK <[email protected]>
74
 * @copyright 2016 Microsoft Corporation
75
 * @license   https://github.com/azure/azure-storage-php/LICENSE
76
 * @link      https://github.com/azure/azure-storage-php
77
 */
78
class TableRestProxy extends ServiceRestProxy implements ITable
79
{
80
    use ServiceRestTrait;
81
82
    /**
83
     * @var Internal\IODataReaderWriter
84
     */
85
    private $odataSerializer;
86
87
    /**
88
     * @var Internal\IMimeReaderWriter
89
     */
90
    private $mimeSerializer;
91
92
    /**
93
     * Creates contexts for batch operations.
94
     *
95
     * @param array $operations The batch operations array.
96
     *
97
     * @return array
98
     *
99
     * @throws \InvalidArgumentException
100
     */
101
    private function createOperationsContexts(array $operations)
102
    {
103
        $contexts = array();
104
105
        foreach ($operations as $operation) {
106
            $context = null;
107
            $type    = $operation->getType();
108
109
            switch ($type) {
110
                case BatchOperationType::INSERT_ENTITY_OPERATION:
111
                case BatchOperationType::UPDATE_ENTITY_OPERATION:
112
                case BatchOperationType::MERGE_ENTITY_OPERATION:
113
                case BatchOperationType::INSERT_REPLACE_ENTITY_OPERATION:
114
                case BatchOperationType::INSERT_MERGE_ENTITY_OPERATION:
115
                    $table   = $operation->getParameter(
116
                        BatchOperationParameterName::BP_TABLE
117
                    );
118
                    $entity  = $operation->getParameter(
119
                        BatchOperationParameterName::BP_ENTITY
120
                    );
121
                    $context = $this->getOperationContext($table, $entity, $type);
122
                    break;
123
    
124
                case BatchOperationType::DELETE_ENTITY_OPERATION:
125
                    $table        = $operation->getParameter(
126
                        BatchOperationParameterName::BP_TABLE
127
                    );
128
                    $partitionKey = $operation->getParameter(
129
                        BatchOperationParameterName::BP_PARTITION_KEY
130
                    );
131
                    $rowKey       = $operation->getParameter(
132
                        BatchOperationParameterName::BP_ROW_KEY
133
                    );
134
                    $etag         = $operation->getParameter(
135
                        BatchOperationParameterName::BP_ETAG
136
                    );
137
                    $options      = new DeleteEntityOptions();
138
                    $options->setETag($etag);
139
                    $context = $this->constructDeleteEntityContext(
140
                        $table,
141
                        $partitionKey,
142
                        $rowKey,
143
                        $options
144
                    );
145
                    break;
146
    
147
                default:
148
                    throw new \InvalidArgumentException();
149
            }
150
151
            $contexts[] = $context;
152
        }
153
154
        return $contexts;
155
    }
156
157
    /**
158
     * Creates operation context for the API.
159
     *
160
     * @param string $table  The table name.
161
     * @param Entity $entity The entity object.
162
     * @param string $type   The API type.
163
     *
164
     * @return \MicrosoftAzure\Storage\Common\Internal\Http\HttpCallContext
165
     *
166
     * @throws \InvalidArgumentException
167
     */
168
    private function getOperationContext($table, Entity $entity, $type)
169
    {
170
        switch ($type) {
171
            case BatchOperationType::INSERT_ENTITY_OPERATION:
172
                return $this->constructInsertEntityContext($table, $entity, null);
173
    
174
            case BatchOperationType::UPDATE_ENTITY_OPERATION:
175
                return $this->constructPutOrMergeEntityContext(
176
                    $table,
177
                    $entity,
178
                    Resources::HTTP_PUT,
179
                    true,
180
                    null
181
                );
182
    
183
            case BatchOperationType::MERGE_ENTITY_OPERATION:
184
                return $this->constructPutOrMergeEntityContext(
185
                    $table,
186
                    $entity,
187
                    Resources::HTTP_MERGE,
188
                    true,
189
                    null
190
                );
191
    
192
            case BatchOperationType::INSERT_REPLACE_ENTITY_OPERATION:
193
                return $this->constructPutOrMergeEntityContext(
194
                    $table,
195
                    $entity,
196
                    Resources::HTTP_PUT,
197
                    false,
198
                    null
199
                );
200
    
201
            case BatchOperationType::INSERT_MERGE_ENTITY_OPERATION:
202
                return $this->constructPutOrMergeEntityContext(
203
                    $table,
204
                    $entity,
205
                    Resources::HTTP_MERGE,
206
                    false,
207
                    null
208
                );
209
    
210
            default:
211
                throw new \InvalidArgumentException();
212
        }
213
    }
214
215
    /**
216
     * Creates MIME part body for batch API.
217
     *
218
     * @param array $operations The batch operations.
219
     * @param array $contexts   The contexts objects.
220
     *
221
     * @return array
222
     *
223
     * @throws \InvalidArgumentException
224
     */
225
    private function createBatchRequestBody(array $operations, array $contexts)
226
    {
227
        $mimeBodyParts = array();
228
        $contentId     = 1;
229
        $count         = count($operations);
230
231
        Validate::isTrue(
232
            count($operations) == count($contexts),
233
            Resources::INVALID_OC_COUNT_MSG
234
        );
235
236
        for ($i = 0; $i < $count; $i++) {
237
            $operation = $operations[$i];
238
            $context   = $contexts[$i];
239
            $type      = $operation->getType();
240
241
            switch ($type) {
242
                case BatchOperationType::INSERT_ENTITY_OPERATION:
243
                case BatchOperationType::UPDATE_ENTITY_OPERATION:
244
                case BatchOperationType::MERGE_ENTITY_OPERATION:
245
                case BatchOperationType::INSERT_REPLACE_ENTITY_OPERATION:
246
                case BatchOperationType::INSERT_MERGE_ENTITY_OPERATION:
247
                    $contentType  = $context->getHeader(Resources::CONTENT_TYPE);
248
                    $body         = $context->getBody();
249
                    $contentType .= ';type=entry';
250
                    $context->addOptionalHeader(Resources::CONTENT_TYPE, $contentType);
251
                    // Use mb_strlen instead of strlen to get the length of the string
252
                    // in bytes instead of the length in chars.
253
                    $context->addOptionalHeader(
254
                        Resources::CONTENT_LENGTH,
255
                        strlen($body)
256
                    );
257
                    break;
258
    
259
                case BatchOperationType::DELETE_ENTITY_OPERATION:
260
                    break;
261
    
262
                default:
263
                    throw new \InvalidArgumentException();
264
            }
265
266
            $context->addOptionalHeader(Resources::CONTENT_ID, $contentId);
267
            $mimeBodyPart    = $context->__toString();
268
            $mimeBodyParts[] = $mimeBodyPart;
269
            $contentId++;
270
        }
271
272
        return $this->mimeSerializer->encodeMimeMultipart($mimeBodyParts);
273
    }
274
275
    /**
276
     * Constructs HTTP call context for deleteEntity API.
277
     *
278
     * @param string              $table        The name of the table.
279
     * @param string              $partitionKey The entity partition key.
280
     * @param string              $rowKey       The entity row key.
281
     * @param DeleteEntityOptions $options      The optional parameters.
282
     *
283
     * @return HttpCallContext
284
     */
285
    private function constructDeleteEntityContext(
286
        $table,
287
        $partitionKey,
288
        $rowKey,
289
        DeleteEntityOptions $options = null
290
    ) {
291
        Validate::isString($table, 'table');
292
        Validate::notNullOrEmpty($table, 'table');
293
        Validate::isTrue(!is_null($partitionKey), Resources::NULL_TABLE_KEY_MSG);
294
        Validate::isTrue(!is_null($rowKey), Resources::NULL_TABLE_KEY_MSG);
295
296
        $method      = Resources::HTTP_DELETE;
297
        $headers     = array();
298
        $queryParams = array();
299
        $statusCode  = Resources::STATUS_NO_CONTENT;
300
        $path        = $this->getEntityPath($table, $partitionKey, $rowKey);
301
302
        if (is_null($options)) {
303
            $options = new DeleteEntityOptions();
304
        }
305
306
        $etagObj = $options->getETag();
307
        $ETag    = !is_null($etagObj);
0 ignored issues
show
introduced by
The condition is_null($etagObj) is always false.
Loading history...
308
        $this->addOptionalHeader(
309
            $headers,
310
            Resources::IF_MATCH,
311
            $ETag ? $etagObj : Resources::ASTERISK
0 ignored issues
show
introduced by
The condition $ETag is always true.
Loading history...
312
        );
313
314
        $options->setLocationMode(LocationMode::PRIMARY_ONLY);
315
316
        $context = new HttpCallContext();
317
        $context->setHeaders($headers);
318
        $context->setMethod($method);
319
        $context->setPath($path);
320
        $context->setQueryParameters($queryParams);
321
        $context->addStatusCode($statusCode);
322
        $context->setBody('');
323
        $context->setServiceOptions($options);
324
325
        return $context;
326
    }
327
328
    /**
329
     * Constructs HTTP call context for updateEntity, mergeEntity,
330
     * insertOrReplaceEntity and insertOrMergeEntity.
331
     *
332
     * @param string              $table   The table name.
333
     * @param Entity              $entity  The entity instance to use.
334
     * @param string              $verb    The HTTP method.
335
     * @param boolean             $useETag The flag to include etag or not.
336
     * @param TableServiceOptions $options The optional parameters.
337
     *
338
     * @return HttpCallContext
339
     */
340
    private function constructPutOrMergeEntityContext(
341
        $table,
342
        Entity $entity,
343
        $verb,
344
        $useETag,
345
        TableServiceOptions $options = null
346
    ) {
347
        Validate::isString($table, 'table');
348
        Validate::notNullOrEmpty($table, 'table');
349
        Validate::notNullOrEmpty($entity, 'entity');
350
        Validate::isTrue($entity->isValid($msg), $msg);
351
352
        $method       = $verb;
353
        $headers      = array();
354
        $queryParams  = array();
355
        $statusCode   = Resources::STATUS_NO_CONTENT;
356
        $partitionKey = $entity->getPartitionKey();
357
        $rowKey       = $entity->getRowKey();
358
        $path         = $this->getEntityPath($table, $partitionKey, $rowKey);
359
        $body         = $this->odataSerializer->getEntity($entity);
360
361
        if (is_null($options)) {
362
            $options = new TableServiceOptions();
363
        }
364
365
        if ($useETag) {
366
            $etag         = $entity->getETag();
367
            $ifMatchValue = is_null($etag) ? Resources::ASTERISK : $etag;
0 ignored issues
show
introduced by
The condition is_null($etag) is always false.
Loading history...
368
369
            $this->addOptionalHeader($headers, Resources::IF_MATCH, $ifMatchValue);
370
        }
371
372
        $this->addOptionalHeader(
373
            $headers,
374
            Resources::CONTENT_TYPE,
375
            Resources::JSON_CONTENT_TYPE
376
        );
377
        $this->addOptionalHeader(
378
            $headers,
379
            Resources::ACCEPT_HEADER,
380
            Resources::JSON_FULL_METADATA_CONTENT_TYPE
381
        );
382
383
        $options->setLocationMode(LocationMode::PRIMARY_ONLY);
384
        $context = new HttpCallContext();
385
        $context->setBody($body);
386
        $context->setHeaders($headers);
387
        $context->setMethod($method);
388
        $context->setPath($path);
389
        $context->setQueryParameters($queryParams);
390
        $context->addStatusCode($statusCode);
391
        $context->setServiceOptions($options);
392
393
        return $context;
394
    }
395
396
    /**
397
     * Constructs HTTP call context for insertEntity API.
398
     *
399
     * @param string                    $table   The name of the table.
400
     * @param Entity                    $entity  The table entity.
401
     * @param TableServiceCreateOptions $options The optional parameters.
402
     *
403
     * @return HttpCallContext
404
     */
405
    private function constructInsertEntityContext(
406
        $table,
407
        Entity $entity,
408
        TableServiceCreateOptions $options = null
409
    ) {
410
        Validate::isString($table, 'table');
411
        Validate::notNullOrEmpty($table, 'table');
412
        Validate::notNullOrEmpty($entity, 'entity');
413
        Validate::isTrue($entity->isValid($msg), $msg);
414
415
        $method      = Resources::HTTP_POST;
416
        $context     = new HttpCallContext();
417
        $headers     = array();
418
        $queryParams = array();
419
        $statusCode  = Resources::STATUS_CREATED;
420
        $path        = $table;
421
        $body        = $this->odataSerializer->getEntity($entity);
422
423
        if (is_null($options)) {
424
            $options = new TableServiceCreateOptions();
425
        }
426
427
        $this->addOptionalHeader(
428
            $headers,
429
            Resources::CONTENT_TYPE,
430
            Resources::JSON_CONTENT_TYPE
431
        );
432
        $this->addOptionalHeader(
433
            $headers,
434
            Resources::ACCEPT_HEADER,
435
            $options->getAccept()
436
        );
437
        $this->addOptionalHeader(
438
            $headers,
439
            Resources::PREFER,
440
            $options->getDoesReturnContent() ? Resources::RETURN_CONTENT : null
441
        );
442
        
443
        $options->setLocationMode(LocationMode::PRIMARY_ONLY);
444
        $context->setBody($body);
445
        $context->setHeaders($headers);
446
        $context->setMethod($method);
447
        $context->setPath($path);
448
        $context->setQueryParameters($queryParams);
449
        $context->addStatusCode($statusCode);
450
        $context->setServiceOptions($options);
451
452
        return $context;
453
    }
454
455
    /**
456
     * Constructs URI path for entity.
457
     *
458
     * @param string $table        The table name.
459
     * @param string $partitionKey The entity's partition key.
460
     * @param string $rowKey       The entity's row key.
461
     *
462
     * @return string
463
     */
464
    private function getEntityPath($table, $partitionKey, $rowKey)
465
    {
466
        $encodedPK = $this->encodeODataUriValue($partitionKey);
467
        $encodedRK = $this->encodeODataUriValue($rowKey);
468
469
        return "$table(PartitionKey='$encodedPK',RowKey='$encodedRK')";
470
    }
471
472
    /**
473
     * Creates a promie that does the actual work for update and merge entity
474
     * APIs.
475
     *
476
     * @param string              $table   The table name.
477
     * @param Entity              $entity  The entity instance to use.
478
     * @param string              $verb    The HTTP method.
479
     * @param boolean             $useETag The flag to include etag or not.
480
     * @param TableServiceOptions $options The optional parameters.
481
     *
482
     * @return \GuzzleHttp\Promise\PromiseInterface
483
     */
484
    private function putOrMergeEntityAsyncImpl(
485
        $table,
486
        Entity $entity,
487
        $verb,
488
        $useETag,
489
        TableServiceOptions $options = null
490
    ) {
491
        $context = $this->constructPutOrMergeEntityContext(
492
            $table,
493
            $entity,
494
            $verb,
495
            $useETag,
496
            $options
497
        );
498
499
        return $this->sendContextAsync($context)->then(function ($response) {
500
            return UpdateEntityResult::create(
501
                HttpFormatter::formatHeaders($response->getHeaders())
502
            );
503
        }, null);
504
    }
505
506
    /**
507
     * Builds filter expression
508
     *
509
     * @param Filter $filter The filter object
510
     *
511
     * @return string
512
     */
513
    private function buildFilterExpression(Filter $filter)
514
    {
515
        $e = Resources::EMPTY_STRING;
516
        $this->buildFilterExpressionRec($filter, $e);
517
518
        return $e;
519
    }
520
521
    /**
522
     * Builds filter expression
523
     *
524
     * @param Filter $filter The filter object
525
     * @param string &$e     The filter expression
526
     *
527
     * @return string
528
     */
529
    private function buildFilterExpressionRec(Filter $filter, &$e)
530
    {
531
        if (is_null($filter)) {
532
            return;
533
        }
534
535
        if ($filter instanceof PropertyNameFilter) {
536
            $e .= $filter->getPropertyName();
537
        } elseif ($filter instanceof ConstantFilter) {
538
            $value = $filter->getValue();
539
            // If the value is null we just append null regardless of the edmType.
540
            if (is_null($value)) {
0 ignored issues
show
introduced by
The condition is_null($value) is always false.
Loading history...
541
                $e .= 'null';
542
            } else {
543
                $type = $filter->getEdmType();
544
                $e   .= EdmType::serializeQueryValue($type, $value);
545
            }
546
        } elseif ($filter instanceof UnaryFilter) {
547
            $e .= $filter->getOperator();
548
            $e .= '(';
549
            $this->buildFilterExpressionRec($filter->getOperand(), $e);
550
            $e .= ')';
551
        } elseif ($filter instanceof BinaryFilter) {
552
            $e .= '(';
553
            $this->buildFilterExpressionRec($filter->getLeft(), $e);
554
            $e .= ' ';
555
            $e .= $filter->getOperator();
556
            $e .= ' ';
557
            $this->buildFilterExpressionRec($filter->getRight(), $e);
558
            $e .= ')';
559
        } elseif ($filter instanceof QueryStringFilter) {
560
            $e .= $filter->getQueryString();
561
        }
562
563
        return $e;
564
    }
565
566
    /**
567
     * Adds query object to the query parameter array
568
     *
569
     * @param array $queryParam The URI query parameters
570
     * @param Query $query      The query object
571
     *
572
     * @return array
573
     */
574
    private function addOptionalQuery(array $queryParam, Query $query)
575
    {
576
        if (!is_null($query)) {
577
            $selectedFields = $query->getSelectFields();
578
            if (!empty($selectedFields)) {
579
                $final = $this->encodeODataUriValues($selectedFields);
580
581
                $this->addOptionalQueryParam(
582
                    $queryParam,
583
                    Resources::QP_SELECT,
584
                    implode(',', $final)
585
                );
586
            }
587
588
            if (!is_null($query->getTop())) {
0 ignored issues
show
introduced by
The condition is_null($query->getTop()) is always false.
Loading history...
589
                $final = strval($this->encodeODataUriValue($query->getTop()));
590
591
                $this->addOptionalQueryParam(
592
                    $queryParam,
593
                    Resources::QP_TOP,
594
                    $final
595
                );
596
            }
597
598
            if (!is_null($query->getFilter())) {
599
                $final = $this->buildFilterExpression($query->getFilter());
600
                $this->addOptionalQueryParam(
601
                    $queryParam,
602
                    Resources::QP_FILTER,
603
                    $final
604
                );
605
            }
606
        }
607
608
        return $queryParam;
609
    }
610
611
    /**
612
     * Encodes OData URI values
613
     *
614
     * @param array $values The OData URL values
615
     *
616
     * @return array
617
     */
618
    private function encodeODataUriValues(array $values)
619
    {
620
        $list = array();
621
622
        foreach ($values as $value) {
623
            $list[] = $this->encodeODataUriValue($value);
624
        }
625
626
        return $list;
627
    }
628
629
    /**
630
     * Encodes OData URI value
631
     *
632
     * @param string $value The OData URL value
633
     *
634
     * @return string
635
     */
636
    private function encodeODataUriValue($value)
637
    {
638
        // Replace each single quote (') with double single quotes ('') not doudle
639
        // quotes (")
640
        $value = str_replace('\'', '\'\'', $value);
641
642
        // Encode the special URL characters
643
        $value = rawurlencode($value);
644
645
        return $value;
646
    }
647
648
    /**
649
     * Initializes new TableRestProxy object.
650
     *
651
     * @param string             $primaryUri      The storage account primary uri.
652
     * @param string             $secondaryUri    The storage account secondary uri.
653
     * @param IODataReaderWriter $odataSerializer The odata serializer.
654
     * @param IMimeReaderWriter  $mimeSerializer  The MIME serializer.
655
     * @param ISerializer        $dataSerializer  The data serializer.
656
     * @param array              $options         Array of options to pass to
657
     *                                            the service
658
     */
659
    public function __construct(
660
        $primaryUri,
661
        $secondaryUri,
662
        IODataReaderWriter $odataSerializer,
663
        IMimeReaderWriter $mimeSerializer,
664
        ISerializer $dataSerializer,
665
        array $options = []
666
    ) {
667
        parent::__construct(
668
            $primaryUri,
669
            $secondaryUri,
670
            Resources::EMPTY_STRING,
671
            $dataSerializer,
672
            $options
673
        );
674
        $this->odataSerializer = $odataSerializer;
675
        $this->mimeSerializer = $mimeSerializer;
676
    }
677
678
    /**
679
     * Quries tables in the given storage account.
680
     *
681
     * @param QueryTablesOptions|string|Filter $options Could be optional
682
     *                                                  parameters, table prefix
683
     *                                                  or filter to apply.
684
     *
685
     * @return QueryTablesResult
686
     *
687
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/query-tables
688
     */
689
    public function queryTables($options = null)
690
    {
691
        return $this->queryTablesAsync($options)->wait();
692
    }
693
694
    /**
695
     * Creates promise to query the tables in the given storage account.
696
     *
697
     * @param QueryTablesOptions|string|Filter $options Could be optional
698
     *                                                  parameters, table prefix
699
     *                                                  or filter to apply.
700
     *
701
     * @return \GuzzleHttp\Promise\PromiseInterface
702
     *
703
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/query-tables
704
     */
705
    public function queryTablesAsync($options = null)
706
    {
707
        $method      = Resources::HTTP_GET;
708
        $headers     = array();
709
        $postParams  = array();
710
        $queryParams = array();
711
        $path        = 'Tables';
712
713
        if (is_null($options)) {
714
            $options = new QueryTablesOptions();
715
        } elseif (is_string($options)) {
716
            $prefix  = $options;
717
            $options = new QueryTablesOptions();
718
            $options->setPrefix($prefix);
719
        } elseif ($options instanceof Filter) {
720
            $filter  = $options;
721
            $options = new QueryTablesOptions();
722
            $options->setFilter($filter);
723
        }
724
725
        $query   = $options->getQuery();
726
        $next    = $options->getNextTableName();
727
        $prefix  = $options->getPrefix();
728
729
        if (!empty($prefix)) {
730
            // Append Max char to end '{' is 1 + 'z' in AsciiTable ==> upperBound
731
            // is prefix + '{'
732
            $prefixFilter = Filter::applyAnd(
733
                Filter::applyGe(
734
                    Filter::applyPropertyName('TableName'),
735
                    Filter::applyConstant($prefix, EdmType::STRING)
736
                ),
737
                Filter::applyLe(
738
                    Filter::applyPropertyName('TableName'),
739
                    Filter::applyConstant($prefix . '{', EdmType::STRING)
740
                )
741
            );
742
743
            if (is_null($query)) {
744
                $query = new Query();
745
            }
746
747
            if (is_null($query->getFilter())) {
748
                // use the prefix filter if the query filter is null
749
                $query->setFilter($prefixFilter);
750
            } else {
751
                // combine and use the prefix filter if the query filter exists
752
                $combinedFilter = Filter::applyAnd(
753
                    $query->getFilter(),
754
                    $prefixFilter
755
                );
756
                $query->setFilter($combinedFilter);
757
            }
758
        }
759
760
        $queryParams = $this->addOptionalQuery($queryParams, $query);
761
762
        $this->addOptionalQueryParam(
763
            $queryParams,
764
            Resources::QP_NEXT_TABLE_NAME,
765
            $next
766
        );
767
        $this->addOptionalHeader(
768
            $headers,
769
            Resources::ACCEPT_HEADER,
770
            $options->getAccept()
771
        );
772
773
        // One can specify the NextTableName option to get table entities starting
774
        // from the specified name. However, there appears to be an issue in the
775
        // Azure Table service where this does not engage on the server unless
776
        // $filter appears in the URL. The current behavior is to just ignore the
777
        // NextTableName options, which is not expected or easily detectable.
778
        if (array_key_exists(Resources::QP_NEXT_TABLE_NAME, $queryParams)
779
            && !array_key_exists(Resources::QP_FILTER, $queryParams)
780
        ) {
781
            $queryParams[Resources::QP_FILTER] = Resources::EMPTY_STRING;
782
        }
783
784
        $odataSerializer = $this->odataSerializer;
785
786
        return $this->sendAsync(
787
            $method,
788
            $headers,
789
            $queryParams,
790
            $postParams,
791
            $path,
792
            Resources::STATUS_OK,
793
            Resources::EMPTY_STRING,
794
            $options
795
        )->then(function ($response) use ($odataSerializer) {
796
            $tables = $odataSerializer->parseTableEntries($response->getBody());
797
            return QueryTablesResult::create(
798
                HttpFormatter::formatHeaders($response->getHeaders()),
799
                $tables
800
            );
801
        }, null);
802
    }
803
804
    /**
805
     * Creates new table in the storage account
806
     *
807
     * @param string                    $table   The name of the table.
808
     * @param TableServiceCreateOptions $options The optional parameters.
809
     *
810
     * @return \Psr\Http\Message\ResponseInterface
811
     *
812
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/create-table
813
     */
814
    public function createTable($table, TableServiceCreateOptions $options = null)
815
    {
816
        return $this->createTableAsync($table, $options)->wait();
817
    }
818
819
    /**
820
     * Creates promise to create new table in the storage account
821
     *
822
     * @param string                    $table   The name of the table.
823
     * @param TableServiceCreateOptions $options The optional parameters.
824
     *
825
     * @return \GuzzleHttp\Promise\PromiseInterface
826
     *
827
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/create-table
828
     */
829
    public function createTableAsync(
830
        $table,
831
        TableServiceCreateOptions $options = null
832
    ) {
833
        Validate::isString($table, 'table');
834
        Validate::notNullOrEmpty($table, 'table');
835
836
        $method      = Resources::HTTP_POST;
837
        $headers     = array();
838
        $postParams  = array();
839
        $queryParams = array();
840
        $path        = 'Tables';
841
        $body        = $this->odataSerializer->getTable($table);
842
843
        if (is_null($options)) {
844
            $options = new TableServiceCreateOptions();
845
        }
846
847
        $this->addOptionalHeader(
848
            $headers,
849
            Resources::CONTENT_TYPE,
850
            Resources::JSON_CONTENT_TYPE
851
        );
852
        $this->addOptionalHeader(
853
            $headers,
854
            Resources::ACCEPT_HEADER,
855
            $options->getAccept()
856
        );
857
858
        $this->addOptionalHeader(
859
            $headers,
860
            Resources::PREFER,
861
            $options->getDoesReturnContent() ? Resources::RETURN_CONTENT : null
862
        );
863
        $options->setLocationMode(LocationMode::PRIMARY_ONLY);
864
865
        return $this->sendAsync(
866
            $method,
867
            $headers,
868
            $queryParams,
869
            $postParams,
870
            $path,
871
            Resources::STATUS_CREATED,
872
            $body,
873
            $options
874
        );
875
    }
876
877
    /**
878
     * Gets the table.
879
     *
880
     * @param string          $table   The name of the table.
881
     * @param GetTableOptions $options The optional parameters.
882
     *
883
     * @return GetTableResult
884
     */
885
    public function getTable($table, GetTableOptions $options = null)
886
    {
887
        return $this->getTableAsync($table, $options)->wait();
888
    }
889
890
    /**
891
     * Creates the promise to get the table.
892
     *
893
     * @param string          $table   The name of the table.
894
     * @param GetTableOptions $options The optional parameters.
895
     *
896
     * @return \GuzzleHttp\Promise\PromiseInterface
897
     */
898
    public function getTableAsync(
899
        $table,
900
        GetTableOptions $options = null
901
    ) {
902
        Validate::isString($table, 'table');
903
        Validate::notNullOrEmpty($table, 'table');
904
905
        $method      = Resources::HTTP_GET;
906
        $headers     = array();
907
        $postParams  = array();
908
        $queryParams = array();
909
        $path        = "Tables('$table')";
910
911
        if (is_null($options)) {
912
            $options = new GetTableOptions();
913
        }
914
915
        $this->addOptionalHeader(
916
            $headers,
917
            Resources::CONTENT_TYPE,
918
            Resources::JSON_CONTENT_TYPE
919
        );
920
        $this->addOptionalHeader(
921
            $headers,
922
            Resources::ACCEPT_HEADER,
923
            $options->getAccept()
924
        );
925
926
        $odataSerializer = $this->odataSerializer;
927
928
        return $this->sendAsync(
929
            $method,
930
            $headers,
931
            $queryParams,
932
            $postParams,
933
            $path,
934
            Resources::STATUS_OK,
935
            Resources::EMPTY_STRING,
936
            $options
937
        )->then(function ($response) use ($odataSerializer) {
938
            return GetTableResult::create($response->getBody(), $odataSerializer);
939
        }, null);
940
    }
941
942
    /**
943
     * Deletes the specified table and any data it contains.
944
     *
945
     * @param string              $table   The name of the table.
946
     * @param TableServiceOptions $options optional parameters
947
     *
948
     * @return void
949
     *
950
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179387.aspx
951
     */
952
    public function deleteTable($table, TableServiceOptions$options = null)
953
    {
954
        $this->deleteTableAsync($table, $options)->wait();
955
    }
956
957
    /**
958
     * Creates promise to delete the specified table and any data it contains.
959
     *
960
     * @param string              $table   The name of the table.
961
     * @param TableServiceOptions $options optional parameters
962
     *
963
     * @return \GuzzleHttp\Promise\PromiseInterface
964
     *
965
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179387.aspx
966
     */
967
    public function deleteTableAsync(
968
        $table,
969
        TableServiceOptions$options = null
970
    ) {
971
        Validate::isString($table, 'table');
972
        Validate::notNullOrEmpty($table, 'table');
973
974
        $method      = Resources::HTTP_DELETE;
975
        $headers     = array();
976
        $postParams  = array();
977
        $queryParams = array();
978
        $path        = "Tables('$table')";
979
980
        if (is_null($options)) {
981
            $options = new TableServiceOptions();
982
        }
983
984
        return $this->sendAsync(
985
            $method,
986
            $headers,
987
            $queryParams,
988
            $postParams,
989
            $path,
990
            Resources::STATUS_NO_CONTENT,
991
            Resources::EMPTY_STRING,
992
            $options
993
        );
994
    }
995
996
    /**
997
     * Quries entities for the given table name
998
     *
999
     * @param string                             $table   The name of
1000
     *                                                    the table.
1001
     * @param QueryEntitiesOptions|string|Filter $options Coule be optional
1002
     *                                                    parameters, query
1003
     *                                                    string or filter to
1004
     *                                                    apply.
1005
     *
1006
     * @return QueryEntitiesResult
1007
     *
1008
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/query-entities
1009
     */
1010
    public function queryEntities($table, $options = null)
1011
    {
1012
        return $this->queryEntitiesAsync($table, $options)->wait();
1013
    }
1014
1015
    /**
1016
     * Quries entities for the given table name
1017
     *
1018
     * @param string                             $table   The name of the table.
1019
     * @param QueryEntitiesOptions|string|Filter $options Coule be optional
1020
     *                                                    parameters, query
1021
     *                                                    string or filter to
1022
     *                                                    apply.
1023
     *
1024
     * @return \GuzzleHttp\Promise\PromiseInterface
1025
     *
1026
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/query-entities
1027
     */
1028
    public function queryEntitiesAsync($table, $options = null)
1029
    {
1030
        Validate::isString($table, 'table');
1031
        Validate::notNullOrEmpty($table, 'table');
1032
1033
        $method      = Resources::HTTP_GET;
1034
        $headers     = array();
1035
        $postParams  = array();
1036
        $queryParams = array();
1037
        $path        = $table;
1038
1039
        if (is_null($options)) {
1040
            $options = new QueryEntitiesOptions();
1041
        } elseif (is_string($options)) {
1042
            $queryString = $options;
1043
            $options     = new QueryEntitiesOptions();
1044
            $options->setFilter(Filter::applyQueryString($queryString));
1045
        } elseif ($options instanceof Filter) {
1046
            $filter  = $options;
1047
            $options = new QueryEntitiesOptions();
1048
            $options->setFilter($filter);
1049
        }
1050
1051
        $queryParams = $this->addOptionalQuery($queryParams, $options->getQuery());
1052
1053
        $this->addOptionalQueryParam(
1054
            $queryParams,
1055
            Resources::QP_NEXT_PK,
1056
            $options->getNextPartitionKey()
1057
        );
1058
        $this->addOptionalQueryParam(
1059
            $queryParams,
1060
            Resources::QP_NEXT_RK,
1061
            $options->getNextRowKey()
1062
        );
1063
1064
        $this->addOptionalHeader(
1065
            $headers,
1066
            Resources::CONTENT_TYPE,
1067
            Resources::JSON_CONTENT_TYPE
1068
        );
1069
1070
        $this->addOptionalHeader(
1071
            $headers,
1072
            Resources::ACCEPT_HEADER,
1073
            $options->getAccept()
1074
        );
1075
1076
        if (!is_null($options->getQuery())) {
1077
            $dsHeader   = Resources::DATA_SERVICE_VERSION;
1078
            $maxdsValue = Resources::MAX_DATA_SERVICE_VERSION_VALUE;
1079
            $fields     = $options->getQuery()->getSelectFields();
1080
            $hasSelect  = !empty($fields);
1081
            if ($hasSelect) {
1082
                $this->addOptionalHeader($headers, $dsHeader, $maxdsValue);
1083
            }
1084
        }
1085
1086
        $odataSerializer = $this->odataSerializer;
1087
1088
        return $this->sendAsync(
1089
            $method,
1090
            $headers,
1091
            $queryParams,
1092
            $postParams,
1093
            $path,
1094
            Resources::STATUS_OK,
1095
            Resources::EMPTY_STRING,
1096
            $options
1097
        )->then(function ($response) use ($odataSerializer) {
1098
            $entities = $odataSerializer->parseEntities($response->getBody());
1099
1100
            return QueryEntitiesResult::create(
1101
                HttpFormatter::formatHeaders($response->getHeaders()),
1102
                $entities
1103
            );
1104
        }, null);
1105
    }
1106
1107
    /**
1108
     * Inserts new entity to the table.
1109
     *
1110
     * @param string                    $table   name of the table.
1111
     * @param Entity                    $entity  table entity.
1112
     * @param TableServiceCreateOptions $options optional parameters.
1113
     *
1114
     * @return InsertEntityResult
1115
     *
1116
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/insert-entity
1117
     */
1118
    public function insertEntity(
1119
        $table,
1120
        Entity $entity,
1121
        TableServiceCreateOptions $options = null
1122
    ) {
1123
        return $this->insertEntityAsync($table, $entity, $options)->wait();
1124
    }
1125
1126
    /**
1127
     * Inserts new entity to the table.
1128
     *
1129
     * @param string                    $table   name of the table.
1130
     * @param Entity                    $entity  table entity.
1131
     * @param TableServiceCreateOptions $options optional parameters.
1132
     *
1133
     * @return \GuzzleHttp\Promise\PromiseInterface
1134
     *
1135
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/insert-entity
1136
     */
1137
    public function insertEntityAsync(
1138
        $table,
1139
        Entity $entity,
1140
        TableServiceCreateOptions $options = null
1141
    ) {
1142
        $context = $this->constructInsertEntityContext(
1143
            $table,
1144
            $entity,
1145
            $options
1146
        );
1147
1148
        $odataSerializer = $this->odataSerializer;
1149
1150
        return $this->sendContextAsync($context)->then(
1151
            function ($response) use ($odataSerializer) {
1152
                $body     = $response->getBody();
1153
                $headers  = HttpFormatter::formatHeaders($response->getHeaders());
1154
                return InsertEntityResult::create(
1155
                    $body,
1156
                    $headers,
1157
                    $odataSerializer
1158
                );
1159
            },
1160
            null
1161
        );
1162
    }
1163
1164
    /**
1165
     * Updates an existing entity or inserts a new entity if it does not exist
1166
     * in the table.
1167
     *
1168
     * @param string              $table   name of the table
1169
     * @param Entity              $entity  table entity
1170
     * @param TableServiceOptions $options optional parameters
1171
     *
1172
     * @return UpdateEntityResult
1173
     *
1174
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452241.aspx
1175
     */
1176
    public function insertOrMergeEntity(
1177
        $table,
1178
        Entity $entity,
1179
        TableServiceOptions $options = null
1180
    ) {
1181
        return $this->insertOrMergeEntityAsync($table, $entity, $options)->wait();
1182
    }
1183
1184
    /**
1185
     * Creates promise to update an existing entity or inserts a new entity if
1186
     * it does not exist in the table.
1187
     *
1188
     * @param string              $table   name of the table
1189
     * @param Entity              $entity  table entity
1190
     * @param TableServiceOptions $options optional parameters
1191
     *
1192
     * @return \GuzzleHttp\Promise\PromiseInterface
1193
     *
1194
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452241.aspx
1195
     */
1196
    public function insertOrMergeEntityAsync(
1197
        $table,
1198
        Entity $entity,
1199
        TableServiceOptions $options = null
1200
    ) {
1201
        return $this->putOrMergeEntityAsyncImpl(
1202
            $table,
1203
            $entity,
1204
            Resources::HTTP_MERGE,
1205
            false,
1206
            $options
1207
        );
1208
    }
1209
1210
    /**
1211
     * Replaces an existing entity or inserts a new entity if it does not exist in
1212
     * the table.
1213
     *
1214
     * @param string              $table   name of the table
1215
     * @param Entity              $entity  table entity
1216
     * @param TableServiceOptions $options optional parameters
1217
     *
1218
     * @return UpdateEntityResult
1219
     *
1220
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452242.aspx
1221
     */
1222
    public function insertOrReplaceEntity(
1223
        $table,
1224
        Entity $entity,
1225
        TableServiceOptions $options = null
1226
    ) {
1227
        return $this->insertOrReplaceEntityAsync(
1228
            $table,
1229
            $entity,
1230
            $options
1231
        )->wait();
1232
    }
1233
1234
    /**
1235
     * Creates a promise to replace an existing entity or inserts a new entity if it does not exist in the table.
1236
     *
1237
     * @param string              $table   name of the table
1238
     * @param Entity              $entity  table entity
1239
     * @param TableServiceOptions $options optional parameters
1240
     *
1241
     * @return \GuzzleHttp\Promise\PromiseInterface
1242
     *
1243
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/hh452242.aspx
1244
     */
1245
    public function insertOrReplaceEntityAsync(
1246
        $table,
1247
        Entity $entity,
1248
        TableServiceOptions $options = null
1249
    ) {
1250
        return $this->putOrMergeEntityAsyncImpl(
1251
            $table,
1252
            $entity,
1253
            Resources::HTTP_PUT,
1254
            false,
1255
            $options
1256
        );
1257
    }
1258
1259
    /**
1260
     * Updates an existing entity in a table. The Update Entity operation replaces
1261
     * the entire entity and can be used to remove properties.
1262
     *
1263
     * @param string              $table   The table name.
1264
     * @param Entity              $entity  The table entity.
1265
     * @param TableServiceOptions $options The optional parameters.
1266
     *
1267
     * @return UpdateEntityResult
1268
     *
1269
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179427.aspx
1270
     */
1271
    public function updateEntity(
1272
        $table,
1273
        Entity $entity,
1274
        TableServiceOptions $options = null
1275
    ) {
1276
        return $this->updateEntityAsync($table, $entity, $options)->wait();
1277
    }
1278
1279
    /**
1280
     * Creates promise to update an existing entity in a table. The Update Entity
1281
     * operation replaces the entire entity and can be used to remove properties.
1282
     *
1283
     * @param string              $table   The table name.
1284
     * @param Entity              $entity  The table entity.
1285
     * @param TableServiceOptions $options The optional parameters.
1286
     *
1287
     * @return \GuzzleHttp\Promise\PromiseInterface
1288
     *
1289
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179427.aspx
1290
     */
1291
    public function updateEntityAsync(
1292
        $table,
1293
        Entity $entity,
1294
        TableServiceOptions $options = null
1295
    ) {
1296
        return $this->putOrMergeEntityAsyncImpl(
1297
            $table,
1298
            $entity,
1299
            Resources::HTTP_PUT,
1300
            true,
1301
            $options
1302
        );
1303
    }
1304
1305
    /**
1306
     * Updates an existing entity by updating the entity's properties. This operation
1307
     * does not replace the existing entity, as the updateEntity operation does.
1308
     *
1309
     * @param string              $table   The table name.
1310
     * @param Entity              $entity  The table entity.
1311
     * @param TableServiceOptions $options The optional parameters.
1312
     *
1313
     * @return Models\UpdateEntityResult
1314
     *
1315
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179392.aspx
1316
     */
1317
    public function mergeEntity(
1318
        $table,
1319
        Entity $entity,
1320
        TableServiceOptions $options = null
1321
    ) {
1322
        return $this->mergeEntityAsync($table, $entity, $options)->wait();
1323
    }
1324
1325
    /**
1326
     * Creates promise to update an existing entity by updating the entity's
1327
     * properties. This operation does not replace the existing entity, as the
1328
     * updateEntity operation does.
1329
     *
1330
     * @param string              $table   The table name.
1331
     * @param Entity              $entity  The table entity.
1332
     * @param TableServiceOptions $options The optional parameters.
1333
     *
1334
     * @return \GuzzleHttp\Promise\PromiseInterface
1335
     *
1336
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179392.aspx
1337
     */
1338
    public function mergeEntityAsync(
1339
        $table,
1340
        Entity $entity,
1341
        TableServiceOptions $options = null
1342
    ) {
1343
        return $this->putOrMergeEntityAsyncImpl(
1344
            $table,
1345
            $entity,
1346
            Resources::HTTP_MERGE,
1347
            true,
1348
            $options
1349
        );
1350
    }
1351
1352
    /**
1353
     * Deletes an existing entity in a table.
1354
     *
1355
     * @param string              $table        The name of the table.
1356
     * @param string              $partitionKey The entity partition key.
1357
     * @param string              $rowKey       The entity row key.
1358
     * @param DeleteEntityOptions $options      The optional parameters.
1359
     *
1360
     * @return void
1361
     *
1362
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd135727.aspx
1363
     */
1364
    public function deleteEntity(
1365
        $table,
1366
        $partitionKey,
1367
        $rowKey,
1368
        DeleteEntityOptions $options = null
1369
    ) {
1370
        $this->deleteEntityAsync($table, $partitionKey, $rowKey, $options)->wait();
1371
    }
1372
1373
    /**
1374
     * Creates promise to delete an existing entity in a table.
1375
     *
1376
     * @param string              $table        The name of the table.
1377
     * @param string              $partitionKey The entity partition key.
1378
     * @param string              $rowKey       The entity row key.
1379
     * @param DeleteEntityOptions $options      The optional parameters.
1380
     *
1381
     * @return \GuzzleHttp\Promise\PromiseInterface
1382
     *
1383
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd135727.aspx
1384
     */
1385
    public function deleteEntityAsync(
1386
        $table,
1387
        $partitionKey,
1388
        $rowKey,
1389
        DeleteEntityOptions $options = null
1390
    ) {
1391
        $context = $this->constructDeleteEntityContext(
1392
            $table,
1393
            $partitionKey,
1394
            $rowKey,
1395
            $options
1396
        );
1397
1398
        return $this->sendContextAsync($context);
1399
    }
1400
1401
    /**
1402
     * Gets table entity.
1403
     *
1404
     * @param string                $table        The name of the table.
1405
     * @param string                $partitionKey The entity partition key.
1406
     * @param string                $rowKey       The entity row key.
1407
     * @param GetEntityOptions|null $options      The optional parameters.
1408
     *
1409
     * @return GetEntityResult
1410
     *
1411
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179421.aspx
1412
     */
1413
    public function getEntity(
1414
        $table,
1415
        $partitionKey,
1416
        $rowKey,
1417
        GetEntityOptions $options = null
1418
    ) {
1419
        return $this->getEntityAsync(
1420
            $table,
1421
            $partitionKey,
1422
            $rowKey,
1423
            $options
1424
        )->wait();
1425
    }
1426
1427
    /**
1428
     * Creates promise to get table entity.
1429
     *
1430
     * @param string                $table        The name of the table.
1431
     * @param string                $partitionKey The entity partition key.
1432
     * @param string                $rowKey       The entity row key.
1433
     * @param GetEntityOptions|null $options      The optional parameters.
1434
     *
1435
     * @return \GuzzleHttp\Promise\PromiseInterface
1436
     *
1437
     * @see http://msdn.microsoft.com/en-us/library/windowsazure/dd179421.aspx
1438
     */
1439
    public function getEntityAsync(
1440
        $table,
1441
        $partitionKey,
1442
        $rowKey,
1443
        GetEntityOptions $options = null
1444
    ) {
1445
        Validate::isString($table, 'table');
1446
        Validate::notNullOrEmpty($table, 'table');
1447
        Validate::isTrue(!is_null($partitionKey), Resources::NULL_TABLE_KEY_MSG);
1448
        Validate::isTrue(!is_null($rowKey), Resources::NULL_TABLE_KEY_MSG);
1449
1450
        $method      = Resources::HTTP_GET;
1451
        $headers     = array();
1452
        $queryParams = array();
1453
        $path        = $this->getEntityPath($table, $partitionKey, $rowKey);
1454
1455
        if (is_null($options)) {
1456
            $options = new GetEntityOptions();
1457
        }
1458
1459
        // TODO: support payload format options
1460
        $this->addOptionalHeader(
1461
            $headers,
1462
            Resources::CONTENT_TYPE,
1463
            Resources::JSON_CONTENT_TYPE
1464
        );
1465
        $this->addOptionalHeader(
1466
            $headers,
1467
            Resources::ACCEPT_HEADER,
1468
            $options->getAccept()
1469
        );
1470
1471
        $context = new HttpCallContext();
1472
        $context->setHeaders($headers);
1473
        $context->setMethod($method);
1474
        $context->setPath($path);
1475
        $context->setQueryParameters($queryParams);
1476
        $context->setStatusCodes(array(Resources::STATUS_OK));
1477
        $context->setServiceOptions($options);
1478
1479
        $odataSerializer = $this->odataSerializer;
1480
1481
        return $this->sendContextAsync($context)->then(
1482
            function ($response) use ($odataSerializer) {
1483
                return GetEntityResult::create(
1484
                    $response->getBody(),
1485
                    $odataSerializer
1486
                );
1487
            },
1488
            null
1489
        );
1490
    }
1491
1492
    /**
1493
     * Does batch of operations on the table service.
1494
     *
1495
     * @param BatchOperations     $batchOperations The operations to apply.
0 ignored issues
show
Bug introduced by
The type MicrosoftAzure\Storage\Table\BatchOperations was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1496
     * @param TableServiceOptions $options         The optional parameters.
1497
     *
1498
     * @return BatchResult
1499
     */
1500
    public function batch(
1501
        Models\BatchOperations $batchOperations,
1502
        Models\TableServiceOptions $options = null
1503
    ) {
1504
        return $this->batchAsync($batchOperations, $options)->wait();
1505
    }
1506
1507
    /**
1508
     * Creates promise that does batch of operations on the table service.
1509
     *
1510
     * @param BatchOperations     $batchOperations The operations to apply.
1511
     * @param TableServiceOptions $options         The optional parameters.
1512
     *
1513
     * @return \GuzzleHttp\Promise\PromiseInterface
1514
     */
1515
    public function batchAsync(
1516
        Models\BatchOperations $batchOperations,
1517
        Models\TableServiceOptions $options = null
1518
    ) {
1519
        Validate::notNullOrEmpty($batchOperations, 'batchOperations');
1520
1521
        $method      = Resources::HTTP_POST;
1522
        $operations  = $batchOperations->getOperations();
1523
        $contexts    = $this->createOperationsContexts($operations);
1524
        $mime        = $this->createBatchRequestBody($operations, $contexts);
1525
        $body        = $mime['body'];
1526
        $headers     = $mime['headers'];
1527
        $postParams  = array();
1528
        $queryParams = array();
1529
        $path        = '$batch';
1530
1531
        if (is_null($options)) {
1532
            $options = new TableServiceOptions();
1533
        }
1534
1535
        $odataSerializer = $this->odataSerializer;
1536
        $mimeSerializer = $this->mimeSerializer;
1537
1538
        $options->setLocationMode(LocationMode::PRIMARY_ONLY);
1539
1540
        $this->addOptionalHeader(
1541
            $headers,
1542
            Resources::ACCEPT_HEADER,
1543
            Resources::JSON_FULL_METADATA_CONTENT_TYPE
1544
        );
1545
1546
        return $this->sendAsync(
1547
            $method,
1548
            $headers,
1549
            $queryParams,
1550
            $postParams,
1551
            $path,
1552
            Resources::STATUS_ACCEPTED,
1553
            $body,
1554
            $options
1555
        )->then(function ($response) use (
1556
            $operations,
1557
            $contexts,
1558
            $odataSerializer,
1559
            $mimeSerializer
1560
        ) {
1561
            return BatchResult::create(
1562
                $response->getBody(),
1563
                $operations,
1564
                $contexts,
1565
                $odataSerializer,
1566
                $mimeSerializer
1567
            );
1568
        }, null);
1569
    }
1570
1571
    /**
1572
     * Gets the access control list (ACL)
1573
     *
1574
     * @param string              $table   The table name.
1575
     * @param TableServiceOptions $options The optional parameters.
1576
     *
1577
     * @return TableACL
1578
     *
1579
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-table-acl
1580
     */
1581
    public function getTableAcl(
1582
        $table,
1583
        Models\TableServiceOptions $options = null
1584
    ) {
1585
        return $this->getTableAclAsync($table, $options)->wait();
1586
    }
1587
1588
    /**
1589
     * Creates the promise to gets the access control list (ACL)
1590
     *
1591
     * @param string              $table   The table name.
1592
     * @param TableServiceOptions $options The optional parameters.
1593
     *
1594
     * @return \GuzzleHttp\Promise\PromiseInterface
1595
     *
1596
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-table-acl
1597
     */
1598
    public function getTableAclAsync(
1599
        $table,
1600
        Models\TableServiceOptions $options = null
1601
    ) {
1602
        Validate::isString($table, 'table');
1603
        
1604
        $method      = Resources::HTTP_GET;
1605
        $headers     = array();
1606
        $postParams  = array();
1607
        $queryParams = array();
1608
        $statusCode  = Resources::STATUS_OK;
0 ignored issues
show
Unused Code introduced by
The assignment to $statusCode is dead and can be removed.
Loading history...
1609
        $path        = $table;
1610
        
1611
        if (is_null($options)) {
1612
            $options = new TableServiceOptions();
1613
        }
1614
        
1615
        $this->addOptionalQueryParam(
1616
            $queryParams,
1617
            Resources::QP_COMP,
1618
            'acl'
1619
        );
1620
1621
        $dataSerializer = $this->dataSerializer;
1622
        
1623
        $promise = $this->sendAsync(
1624
            $method,
1625
            $headers,
1626
            $queryParams,
1627
            $postParams,
1628
            $path,
1629
            Resources::STATUS_OK,
1630
            Resources::EMPTY_STRING,
1631
            $options
1632
        );
1633
1634
        return $promise->then(function ($response) use ($dataSerializer) {
1635
            $parsed       = $dataSerializer->unserialize($response->getBody());
1636
            return TableACL::create($parsed);
1637
        }, null);
1638
    }
1639
    
1640
    /**
1641
     * Sets the ACL.
1642
     *
1643
     * @param string              $table   name
1644
     * @param TableACL            $acl     access control list for Table
1645
     * @param TableServiceOptions $options optional parameters
1646
     *
1647
     * @return void
1648
     *
1649
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-table-acl
1650
     */
1651
    public function setTableAcl(
1652
        $table,
1653
        TableACL $acl,
1654
        TableServiceOptions $options = null
1655
    ) {
1656
        $this->setTableAclAsync($table, $acl, $options)->wait();
1657
    }
1658
1659
    /**
1660
     * Creates promise to set the ACL
1661
     *
1662
     * @param string              $table   name
1663
     * @param TableACL            $acl     access control list for Table
1664
     * @param TableServiceOptions $options optional parameters
1665
     *
1666
     * @return \GuzzleHttp\Promise\PromiseInterface
1667
     *
1668
     * @see https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-table-acl
1669
     */
1670
    public function setTableAclAsync(
1671
        $table,
1672
        TableACL $acl,
1673
        TableServiceOptions $options = null
1674
    ) {
1675
        Validate::isString($table, 'table');
1676
        Validate::notNullOrEmpty($acl, 'acl');
1677
        
1678
        $method      = Resources::HTTP_PUT;
1679
        $headers     = array();
1680
        $postParams  = array();
1681
        $queryParams = array();
1682
        $body        = $acl->toXml($this->dataSerializer);
1683
        $path        = $table;
1684
        
1685
        if (is_null($options)) {
1686
            $options = new TableServiceOptions();
1687
        }
1688
        
1689
        $this->addOptionalQueryParam(
1690
            $queryParams,
1691
            Resources::QP_COMP,
1692
            'acl'
1693
        );
1694
1695
        $options->setLocationMode(LocationMode::PRIMARY_ONLY);
1696
        
1697
        return $this->sendAsync(
1698
            $method,
1699
            $headers,
1700
            $queryParams,
1701
            $postParams,
1702
            $path,
1703
            Resources::STATUS_NO_CONTENT,
1704
            $body,
1705
            $options
1706
        );
1707
    }
1708
}
1709