ClientResolver::_missing_version()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 15
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 15
rs 9.8333
1
<?php
2
namespace Aws;
3
4
use Aws\Api\Validator;
5
use Aws\Api\ApiProvider;
6
use Aws\Api\Service;
7
use Aws\Credentials\Credentials;
8
use Aws\Credentials\CredentialsInterface;
9
use Aws\Endpoint\Partition;
10
use Aws\Endpoint\PartitionEndpointProvider;
11
use Aws\Endpoint\PartitionProviderInterface;
0 ignored issues
show
Bug introduced by
The type Aws\Endpoint\PartitionProviderInterface 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...
12
use Aws\Signature\SignatureProvider;
13
use Aws\Endpoint\EndpointProvider;
14
use Aws\Credentials\CredentialProvider;
15
use GuzzleHttp\Promise;
16
use InvalidArgumentException as IAE;
17
use Psr\Http\Message\RequestInterface;
18
19
/**
20
 * @internal Resolves a hash of client arguments to construct a client.
21
 */
22
class ClientResolver
23
{
24
    /** @var array */
25
    private $argDefinitions;
26
27
    /** @var array Map of types to a corresponding function */
28
    private static $typeMap = [
29
        'resource' => 'is_resource',
30
        'callable' => 'is_callable',
31
        'int'      => 'is_int',
32
        'bool'     => 'is_bool',
33
        'string'   => 'is_string',
34
        'object'   => 'is_object',
35
        'array'    => 'is_array',
36
    ];
37
38
    private static $defaultArgs = [
39
        'service' => [
40
            'type'     => 'value',
41
            'valid'    => ['string'],
42
            'doc'      => 'Name of the service to utilize. This value will be supplied by default when using one of the SDK clients (e.g., Aws\\S3\\S3Client).',
43
            'required' => true,
44
            'internal' => true
45
        ],
46
        'exception_class' => [
47
            'type'     => 'value',
48
            'valid'    => ['string'],
49
            'doc'      => 'Exception class to create when an error occurs.',
50
            'default'  => 'Aws\Exception\AwsException',
51
            'internal' => true
52
        ],
53
        'scheme' => [
54
            'type'     => 'value',
55
            'valid'    => ['string'],
56
            'default'  => 'https',
57
            'doc'      => 'URI scheme to use when connecting connect. The SDK will utilize "https" endpoints (i.e., utilize SSL/TLS connections) by default. You can attempt to connect to a service over an unencrypted "http" endpoint by setting ``scheme`` to "http".',
58
        ],
59
        'endpoint' => [
60
            'type'  => 'value',
61
            'valid' => ['string'],
62
            'doc'   => 'The full URI of the webservice. This is only required when connecting to a custom endpoint (e.g., a local version of S3).',
63
            'fn'    => [__CLASS__, '_apply_endpoint'],
64
        ],
65
        'region' => [
66
            'type'     => 'value',
67
            'valid'    => ['string'],
68
            'required' => [__CLASS__, '_missing_region'],
69
            'doc'      => 'Region to connect to. See http://docs.aws.amazon.com/general/latest/gr/rande.html for a list of available regions.',
70
        ],
71
        'version' => [
72
            'type'     => 'value',
73
            'valid'    => ['string'],
74
            'required' => [__CLASS__, '_missing_version'],
75
            'doc'      => 'The version of the webservice to utilize (e.g., 2006-03-01).',
76
        ],
77
        'signature_provider' => [
78
            'type'    => 'value',
79
            'valid'   => ['callable'],
80
            'doc'     => 'A callable that accepts a signature version name (e.g., "v4"), a service name, and region, and  returns a SignatureInterface object or null. This provider is used to create signers utilized by the client. See Aws\\Signature\\SignatureProvider for a list of built-in providers',
81
            'default' => [__CLASS__, '_default_signature_provider'],
82
        ],
83
        'api_provider' => [
84
            'type'     => 'value',
85
            'valid'    => ['callable'],
86
            'doc'      => 'An optional PHP callable that accepts a type, service, and version argument, and returns an array of corresponding configuration data. The type value can be one of api, waiter, or paginator.',
87
            'fn'       => [__CLASS__, '_apply_api_provider'],
88
            'default'  => [ApiProvider::class, 'defaultProvider'],
89
        ],
90
        'endpoint_provider' => [
91
            'type'     => 'value',
92
            'valid'    => ['callable'],
93
            'fn'       => [__CLASS__, '_apply_endpoint_provider'],
94
            'doc'      => 'An optional PHP callable that accepts a hash of options including a "service" and "region" key and returns NULL or a hash of endpoint data, of which the "endpoint" key is required. See Aws\\Endpoint\\EndpointProvider for a list of built-in providers.',
95
            'default' => [__CLASS__, '_default_endpoint_provider'],
96
        ],
97
        'serializer' => [
98
            'default'   => [__CLASS__, '_default_serializer'],
99
            'fn'        => [__CLASS__, '_apply_serializer'],
100
            'internal'  => true,
101
            'type'      => 'value',
102
            'valid'     => ['callable'],
103
        ],
104
        'signature_version' => [
105
            'type'    => 'config',
106
            'valid'   => ['string'],
107
            'doc'     => 'A string representing a custom signature version to use with a service (e.g., v4). Note that per/operation signature version MAY override this requested signature version.',
108
            'default' => [__CLASS__, '_default_signature_version'],
109
        ],
110
        'signing_name' => [
111
            'type'    => 'config',
112
            'valid'   => ['string'],
113
            'doc'     => 'A string representing a custom service name to be used when calculating a request signature.',
114
            'default' => [__CLASS__, '_default_signing_name'],
115
        ],
116
        'signing_region' => [
117
            'type'    => 'config',
118
            'valid'   => ['string'],
119
            'doc'     => 'A string representing a custom region name to be used when calculating a request signature.',
120
            'default' => [__CLASS__, '_default_signing_region'],
121
        ],
122
        'profile' => [
123
            'type'  => 'config',
124
            'valid' => ['string'],
125
            'doc'   => 'Allows you to specify which profile to use when credentials are created from the AWS credentials file in your HOME directory. This setting overrides the AWS_PROFILE environment variable. Note: Specifying "profile" will cause the "credentials" key to be ignored.',
126
            'fn'    => [__CLASS__, '_apply_profile'],
127
        ],
128
        'credentials' => [
129
            'type'    => 'value',
130
            'valid'   => [CredentialsInterface::class, CacheInterface::class, 'array', 'bool', 'callable'],
131
            'doc'     => 'Specifies the credentials used to sign requests. Provide an Aws\Credentials\CredentialsInterface object, an associative array of "key", "secret", and an optional "token" key, `false` to use null credentials, or a callable credentials provider used to create credentials or return null. See Aws\\Credentials\\CredentialProvider for a list of built-in credentials providers. If no credentials are provided, the SDK will attempt to load them from the environment.',
132
            'fn'      => [__CLASS__, '_apply_credentials'],
133
            'default' => [CredentialProvider::class, 'defaultProvider'],
134
        ],
135
        'stats' => [
136
            'type'  => 'value',
137
            'valid' => ['bool', 'array'],
138
            'default' => false,
139
            'doc'   => 'Set to true to gather transfer statistics on requests sent. Alternatively, you can provide an associative array with the following keys: retries: (bool) Set to false to disable reporting on retries attempted; http: (bool) Set to true to enable collecting statistics from lower level HTTP adapters (e.g., values returned in GuzzleHttp\TransferStats). HTTP handlers must support an http_stats_receiver option for this to have an effect; timer: (bool) Set to true to enable a command timer that reports the total wall clock time spent on an operation in seconds.',
140
            'fn'    => [__CLASS__, '_apply_stats'],
141
        ],
142
        'retries' => [
143
            'type'    => 'value',
144
            'valid'   => ['int'],
145
            'doc'     => 'Configures the maximum number of allowed retries for a client (pass 0 to disable retries). ',
146
            'fn'      => [__CLASS__, '_apply_retries'],
147
            'default' => 3,
148
        ],
149
        'validate' => [
150
            'type'    => 'value',
151
            'valid'   => ['bool', 'array'],
152
            'default' => true,
153
            'doc'     => 'Set to false to disable client-side parameter validation. Set to true to utilize default validation constraints. Set to an associative array of validation options to enable specific validation constraints.',
154
            'fn'      => [__CLASS__, '_apply_validate'],
155
        ],
156
        'debug' => [
157
            'type'  => 'value',
158
            'valid' => ['bool', 'array'],
159
            'doc'   => 'Set to true to display debug information when sending requests. Alternatively, you can provide an associative array with the following keys: logfn: (callable) Function that is invoked with log messages; stream_size: (int) When the size of a stream is greater than this number, the stream data will not be logged (set to "0" to not log any stream data); scrub_auth: (bool) Set to false to disable the scrubbing of auth data from the logged messages; http: (bool) Set to false to disable the "debug" feature of lower level HTTP adapters (e.g., verbose curl output).',
160
            'fn'    => [__CLASS__, '_apply_debug'],
161
        ],
162
        'http' => [
163
            'type'    => 'value',
164
            'valid'   => ['array'],
165
            'default' => [],
166
            'doc'     => 'Set to an array of SDK request options to apply to each request (e.g., proxy, verify, etc.).',
167
        ],
168
        'http_handler' => [
169
            'type'    => 'value',
170
            'valid'   => ['callable'],
171
            'doc'     => 'An HTTP handler is a function that accepts a PSR-7 request object and returns a promise that is fulfilled with a PSR-7 response object or rejected with an array of exception data. NOTE: This option supersedes any provided "handler" option.',
172
            'fn'      => [__CLASS__, '_apply_http_handler']
173
        ],
174
        'handler' => [
175
            'type'     => 'value',
176
            'valid'    => ['callable'],
177
            'doc'      => 'A handler that accepts a command object, request object and returns a promise that is fulfilled with an Aws\ResultInterface object or rejected with an Aws\Exception\AwsException. A handler does not accept a next handler as it is terminal and expected to fulfill a command. If no handler is provided, a default Guzzle handler will be utilized.',
178
            'fn'       => [__CLASS__, '_apply_handler'],
179
            'default'  => [__CLASS__, '_default_handler']
180
        ],
181
        'ua_append' => [
182
            'type'     => 'value',
183
            'valid'    => ['string', 'array'],
184
            'doc'      => 'Provide a string or array of strings to send in the User-Agent header.',
185
            'fn'       => [__CLASS__, '_apply_user_agent'],
186
            'default'  => [],
187
        ],
188
        'idempotency_auto_fill' => [
189
            'type'      => 'value',
190
            'valid'     => ['bool', 'callable'],
191
            'doc'       => 'Set to false to disable SDK to populate parameters that enabled \'idempotencyToken\' trait with a random UUID v4 value on your behalf. Using default value \'true\' still allows parameter value to be overwritten when provided. Note: auto-fill only works when cryptographically secure random bytes generator functions(random_bytes, openssl_random_pseudo_bytes or mcrypt_create_iv) can be found. You may also provide a callable source of random bytes.',
192
            'default'   => true,
193
            'fn'        => [__CLASS__, '_apply_idempotency_auto_fill']
194
        ],
195
    ];
196
197
    /**
198
     * Gets an array of default client arguments, each argument containing a
199
     * hash of the following:
200
     *
201
     * - type: (string, required) option type described as follows:
202
     *   - value: The default option type.
203
     *   - config: The provided value is made available in the client's
204
     *     getConfig() method.
205
     * - valid: (array, required) Valid PHP types or class names. Note: null
206
     *   is not an allowed type.
207
     * - required: (bool, callable) Whether or not the argument is required.
208
     *   Provide a function that accepts an array of arguments and returns a
209
     *   string to provide a custom error message.
210
     * - default: (mixed) The default value of the argument if not provided. If
211
     *   a function is provided, then it will be invoked to provide a default
212
     *   value. The function is provided the array of options and is expected
213
     *   to return the default value of the option. The default value can be a
214
     *   closure and can not be a callable string that is not  part of the
215
     *   defaultArgs array.
216
     * - doc: (string) The argument documentation string.
217
     * - fn: (callable) Function used to apply the argument. The function
218
     *   accepts the provided value, array of arguments by reference, and an
219
     *   event emitter.
220
     *
221
     * Note: Order is honored and important when applying arguments.
222
     *
223
     * @return array
224
     */
225
    public static function getDefaultArguments()
226
    {
227
        return self::$defaultArgs;
228
    }
229
230
    /**
231
     * @param array $argDefinitions Client arguments.
232
     */
233
    public function __construct(array $argDefinitions)
234
    {
235
        $this->argDefinitions = $argDefinitions;
236
    }
237
238
    /**
239
     * Resolves client configuration options and attached event listeners.
240
     * Check for missing keys in passed arguments
241
     *
242
     * @param array       $args Provided constructor arguments.
243
     * @param HandlerList $list Handler list to augment.
244
     *
245
     * @return array Returns the array of provided options.
246
     * @throws \InvalidArgumentException
247
     * @see Aws\AwsClient::__construct for a list of available options.
248
     */
249
    public function resolve(array $args, HandlerList $list)
250
    {
251
        $args['config'] = [];
252
        foreach ($this->argDefinitions as $key => $a) {
253
            // Add defaults, validate required values, and skip if not set.
254
            if (!isset($args[$key])) {
255
                if (isset($a['default'])) {
256
                    // Merge defaults in when not present.
257
                    if (is_callable($a['default'])
258
                        && (
259
                            is_array($a['default'])
260
                            || $a['default'] instanceof \Closure
261
                        )
262
                    ) {
263
                        $args[$key] = $a['default']($args);
264
                    } else {
265
                        $args[$key] = $a['default'];
266
                    }
267
                } elseif (empty($a['required'])) {
268
                    continue;
269
                } else {
270
                    $this->throwRequired($args);
271
                }
272
            }
273
274
            // Validate the types against the provided value.
275
            foreach ($a['valid'] as $check) {
276
                if (isset(self::$typeMap[$check])) {
277
                    $fn = self::$typeMap[$check];
278
                    if ($fn($args[$key])) {
279
                        goto is_valid;
280
                    }
281
                } elseif ($args[$key] instanceof $check) {
282
                    goto is_valid;
283
                }
284
            }
285
286
            $this->invalidType($key, $args[$key]);
287
288
            // Apply the value
289
            is_valid:
290
            if (isset($a['fn'])) {
291
                $a['fn']($args[$key], $args, $list);
292
            }
293
294
            if ($a['type'] === 'config') {
295
                $args['config'][$key] = $args[$key];
296
            }
297
        }
298
299
        return $args;
300
    }
301
302
    /**
303
     * Creates a verbose error message for an invalid argument.
304
     *
305
     * @param string $name        Name of the argument that is missing.
306
     * @param array  $args        Provided arguments
307
     * @param bool   $useRequired Set to true to show the required fn text if
308
     *                            available instead of the documentation.
309
     * @return string
310
     */
311
    private function getArgMessage($name, $args = [], $useRequired = false)
312
    {
313
        $arg = $this->argDefinitions[$name];
314
        $msg = '';
315
        $modifiers = [];
316
        if (isset($arg['valid'])) {
317
            $modifiers[] = implode('|', $arg['valid']);
318
        }
319
        if (isset($arg['choice'])) {
320
            $modifiers[] = 'One of ' . implode(', ', $arg['choice']);
321
        }
322
        if ($modifiers) {
323
            $msg .= '(' . implode('; ', $modifiers) . ')';
324
        }
325
        $msg = wordwrap("{$name}: {$msg}", 75, "\n  ");
326
327
        if ($useRequired && is_callable($arg['required'])) {
328
            $msg .= "\n\n  ";
329
            $msg .= str_replace("\n", "\n  ", call_user_func($arg['required'], $args));
330
        } elseif (isset($arg['doc'])) {
331
            $msg .= wordwrap("\n\n  {$arg['doc']}", 75, "\n  ");
332
        }
333
334
        return $msg;
335
    }
336
337
    /**
338
     * Throw when an invalid type is encountered.
339
     *
340
     * @param string $name     Name of the value being validated.
341
     * @param mixed  $provided The provided value.
342
     * @throws \InvalidArgumentException
343
     */
344
    private function invalidType($name, $provided)
345
    {
346
        $expected = implode('|', $this->argDefinitions[$name]['valid']);
347
        $msg = "Invalid configuration value "
348
            . "provided for \"{$name}\". Expected {$expected}, but got "
349
            . describe_type($provided) . "\n\n"
350
            . $this->getArgMessage($name);
351
        throw new IAE($msg);
352
    }
353
354
    /**
355
     * Throws an exception for missing required arguments.
356
     *
357
     * @param array $args Passed in arguments.
358
     * @throws \InvalidArgumentException
359
     */
360
    private function throwRequired(array $args)
361
    {
362
        $missing = [];
363
        foreach ($this->argDefinitions as $k => $a) {
364
            if (empty($a['required'])
365
                || isset($a['default'])
366
                || array_key_exists($k, $args)
367
            ) {
368
                continue;
369
            }
370
            $missing[] = $this->getArgMessage($k, $args, true);
371
        }
372
        $msg = "Missing required client configuration options: \n\n";
373
        $msg .= implode("\n\n", $missing);
374
        throw new IAE($msg);
375
    }
376
377
    public static function _apply_retries($value, array &$args, HandlerList $list)
378
    {
379
        if ($value) {
380
            $decider = RetryMiddleware::createDefaultDecider($value);
381
            $list->appendSign(
382
                Middleware::retry($decider, null, $args['stats']['retries']),
383
                'retry'
384
            );
385
        }
386
    }
387
388
    public static function _apply_credentials($value, array &$args)
389
    {
390
        if (is_callable($value)) {
391
            return;
392
        } elseif ($value instanceof CredentialsInterface) {
393
            $args['credentials'] = CredentialProvider::fromCredentials($value);
394
        } elseif (is_array($value)
395
            && isset($value['key'])
396
            && isset($value['secret'])
397
        ) {
398
            $args['credentials'] = CredentialProvider::fromCredentials(
399
                new Credentials(
400
                    $value['key'],
401
                    $value['secret'],
402
                    isset($value['token']) ? $value['token'] : null,
403
                    isset($value['expires']) ? $value['expires'] : null
404
                )
405
            );
406
        } elseif ($value === false) {
407
            $args['credentials'] = CredentialProvider::fromCredentials(
408
                new Credentials('', '')
409
            );
410
            $args['config']['signature_version'] = 'anonymous';
411
        } elseif ($value instanceof CacheInterface) {
412
            $args['credentials'] = CredentialProvider::defaultProvider($args);
413
        } else {
414
            throw new IAE('Credentials must be an instance of '
415
                . 'Aws\Credentials\CredentialsInterface, an associative '
416
                . 'array that contains "key", "secret", and an optional "token" '
417
                . 'key-value pairs, a credentials provider function, or false.');
418
        }
419
    }
420
421
    public static function _apply_api_provider(callable $value, array &$args)
422
    {
423
        $api = new Service(
424
            ApiProvider::resolve(
425
                $value,
426
                'api',
427
                $args['service'],
428
                $args['version']
429
            ),
430
            $value
431
        );
432
433
        if (
434
            empty($args['config']['signing_name'])
435
            && isset($api['metadata']['signingName'])
436
        ) {
437
            $args['config']['signing_name'] = $api['metadata']['signingName'];
438
        }
439
440
        $args['api'] = $api;
441
        $args['parser'] = Service::createParser($api);
442
        $args['error_parser'] = Service::createErrorParser($api->getProtocol());
443
    }
444
445
    public static function _apply_endpoint_provider(callable $value, array &$args)
446
    {
447
        if (!isset($args['endpoint'])) {
448
            $endpointPrefix = isset($args['api']['metadata']['endpointPrefix'])
449
                ? $args['api']['metadata']['endpointPrefix']
450
                : $args['service'];
451
452
            // Invoke the endpoint provider and throw if it does not resolve.
453
            $result = EndpointProvider::resolve($value, [
454
                'service' => $endpointPrefix,
455
                'region'  => $args['region'],
456
                'scheme'  => $args['scheme']
457
            ]);
458
459
            $args['endpoint'] = $result['endpoint'];
460
461
            if (
462
                empty($args['config']['signature_version'])
463
                && isset($result['signatureVersion'])
464
            ) {
465
                $args['config']['signature_version']
466
                    = $result['signatureVersion'];
467
            }
468
469
            if (
470
                empty($args['config']['signing_region'])
471
                && isset($result['signingRegion'])
472
            ) {
473
                $args['config']['signing_region'] = $result['signingRegion'];
474
            }
475
476
            if (
477
                empty($args['config']['signing_name'])
478
                && isset($result['signingName'])
479
            ) {
480
                $args['config']['signing_name'] = $result['signingName'];
481
            }
482
        }
483
    }
484
485
    public static function _apply_serializer($value, array &$args, HandlerList $list)
486
    {
487
        $list->prependBuild(Middleware::requestBuilder($value), 'builder');
488
    }
489
490
    public static function _apply_debug($value, array &$args, HandlerList $list)
491
    {
492
        if ($value !== false) {
493
            $list->interpose(new TraceMiddleware($value === true ? [] : $value));
494
        }
495
    }
496
497
    public static function _apply_stats($value, array &$args, HandlerList $list)
498
    {
499
        // Create an array of stat collectors that are disabled (set to false)
500
        // by default. If the user has passed in true, enable all stat
501
        // collectors.
502
        $defaults = array_fill_keys(
503
            ['http', 'retries', 'timer'],
504
            $value === true
505
        );
506
        $args['stats'] = is_array($value)
507
            ? array_replace($defaults, $value)
508
            : $defaults;
509
510
        if ($args['stats']['timer']) {
511
            $list->prependInit(Middleware::timer(), 'timer');
512
        }
513
    }
514
515
    public static function _apply_profile($_, array &$args)
516
    {
517
        $args['credentials'] = CredentialProvider::ini($args['profile']);
518
    }
519
520
    public static function _apply_validate($value, array &$args, HandlerList $list)
521
    {
522
        if ($value === false) {
523
            return;
524
        }
525
526
        $validator = $value === true
527
            ? new Validator()
528
            : new Validator($value);
529
        $list->appendValidate(
530
            Middleware::validation($args['api'], $validator),
531
            'validation'
532
        );
533
    }
534
535
    public static function _apply_handler($value, array &$args, HandlerList $list)
536
    {
537
        $list->setHandler($value);
538
    }
539
540
    public static function _default_handler(array &$args)
541
    {
542
        return new WrappedHttpHandler(
543
            default_http_handler(),
544
            $args['parser'],
545
            $args['error_parser'],
546
            $args['exception_class'],
547
            $args['stats']['http']
548
        );
549
    }
550
551
    public static function _apply_http_handler($value, array &$args, HandlerList $list)
552
    {
553
        $args['handler'] = new WrappedHttpHandler(
554
            $value,
555
            $args['parser'],
556
            $args['error_parser'],
557
            $args['exception_class'],
558
            $args['stats']['http']
559
        );
560
    }
561
562
    public static function _apply_user_agent($value, array &$args, HandlerList $list)
563
    {
564
        if (!is_array($value)) {
565
            $value = [$value];
566
        }
567
568
        $value = array_map('strval', $value);
569
570
        array_unshift($value, 'aws-sdk-php/' . Sdk::VERSION);
571
        $args['ua_append'] = $value;
572
573
        $list->appendBuild(static function (callable $handler) use ($value) {
574
            return function (
575
                CommandInterface $command,
576
                RequestInterface $request
577
            ) use ($handler, $value) {
578
                return $handler($command, $request->withHeader(
579
                    'User-Agent',
580
                    implode(' ', array_merge(
581
                        $value,
582
                        $request->getHeader('User-Agent')
583
                    ))
584
                ));
585
            };
586
        });
587
    }
588
589
    public static function _apply_endpoint($value, array &$args, HandlerList $list)
590
    {
591
        $parts = parse_url($value);
592
        if (empty($parts['scheme']) || empty($parts['host'])) {
593
            throw new IAE(
594
                'Endpoints must be full URIs and include a scheme and host'
595
            );
596
        }
597
598
        $args['endpoint'] = $value;
599
    }
600
601
    public static function _apply_idempotency_auto_fill(
602
        $value,
603
        array &$args,
604
        HandlerList $list
605
    ) {
606
        $enabled = false;
607
        $generator = null;
608
609
610
        if (is_bool($value)) {
611
            $enabled = $value;
612
        } elseif (is_callable($value)) {
613
            $enabled = true;
614
            $generator = $value;
615
        }
616
617
        if ($enabled) {
618
            $list->prependInit(
619
                IdempotencyTokenMiddleware::wrap($args['api'], $generator),
620
                'idempotency_auto_fill'
621
            );
622
        }
623
    }
624
625
    public static function _default_endpoint_provider(array $args)
626
    {
627
        return PartitionEndpointProvider::defaultProvider()
628
            ->getPartition($args['region'], $args['service']);
629
    }
630
631
    public static function _default_serializer(array $args)
632
    {
633
        return Service::createSerializer(
634
            $args['api'],
635
            $args['endpoint']
636
        );
637
    }
638
639
    public static function _default_signature_provider()
640
    {
641
        return SignatureProvider::defaultProvider();
642
    }
643
644
    public static function _default_signature_version(array &$args)
645
    {
646
        if (isset($args['config']['signature_version'])) {
647
            return $args['config']['signature_version'];
648
        }
649
650
        $args['__partition_result'] = isset($args['__partition_result'])
651
            ? isset($args['__partition_result'])
652
            : call_user_func(PartitionEndpointProvider::defaultProvider(), [
653
                'service' => $args['service'],
654
                'region' => $args['region'],
655
            ]);
656
657
        return isset($args['__partition_result']['signatureVersion'])
658
            ? $args['__partition_result']['signatureVersion']
659
            : $args['api']->getSignatureVersion();
660
    }
661
662
    public static function _default_signing_name(array &$args)
663
    {
664
        if (isset($args['config']['signing_name'])) {
665
            return $args['config']['signing_name'];
666
        }
667
668
        $args['__partition_result'] = isset($args['__partition_result'])
669
            ? isset($args['__partition_result'])
670
            : call_user_func(PartitionEndpointProvider::defaultProvider(), [
671
                'service' => $args['service'],
672
                'region' => $args['region'],
673
            ]);
674
675
        if (isset($args['__partition_result']['signingName'])) {
676
            return $args['__partition_result']['signingName'];
677
        }
678
679
        if ($signingName = $args['api']->getSigningName()) {
680
            return $signingName;
681
        }
682
683
        return $args['service'];
684
    }
685
686
    public static function _default_signing_region(array &$args)
687
    {
688
        if (isset($args['config']['signing_region'])) {
689
            return $args['config']['signing_region'];
690
        }
691
692
        $args['__partition_result'] = isset($args['__partition_result'])
693
            ? isset($args['__partition_result'])
694
            : call_user_func(PartitionEndpointProvider::defaultProvider(), [
695
                'service' => $args['service'],
696
                'region' => $args['region'],
697
            ]);
698
699
        return isset($args['__partition_result']['signingRegion'])
700
            ? $args['__partition_result']['signingRegion']
701
            : $args['region'];
702
    }
703
704
    public static function _missing_version(array $args)
705
    {
706
        $service = isset($args['service']) ? $args['service'] : '';
707
        $versions = ApiProvider::defaultProvider()->getVersions($service);
708
        $versions = implode("\n", array_map(function ($v) {
709
            return "* \"$v\"";
710
        }, $versions)) ?: '* (none found)';
711
712
        return <<<EOT
713
A "version" configuration value is required. Specifying a version constraint
714
ensures that your code will not be affected by a breaking change made to the
715
service. For example, when using Amazon S3, you can lock your API version to
716
"2006-03-01".
717
718
Your build of the SDK has the following version(s) of "{$service}": {$versions}
719
720
You may provide "latest" to the "version" configuration value to utilize the
721
most recent available API version that your client's API provider can find.
722
Note: Using 'latest' in a production application is not recommended.
723
724
A list of available API versions can be found on each client's API documentation
725
page: http://docs.aws.amazon.com/aws-sdk-php/v3/api/index.html. If you are
726
unable to load a specific API version, then you may need to update your copy of
727
the SDK.
728
EOT;
729
    }
730
731
    public static function _missing_region(array $args)
732
    {
733
        $service = isset($args['service']) ? $args['service'] : '';
734
735
        return <<<EOT
736
A "region" configuration value is required for the "{$service}" service
737
(e.g., "us-west-2"). A list of available public regions and endpoints can be
738
found at http://docs.aws.amazon.com/general/latest/gr/rande.html.
739
EOT;
740
    }
741
}
742