commercetools /
commercetools-php-sdk
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
| 1 | <?php |
||||
| 2 | |||||
| 3 | namespace Commercetools\Core\Client; |
||||
| 4 | |||||
| 5 | use Commercetools\Core\Cache\CacheAdapterFactory; |
||||
| 6 | use Commercetools\Core\Client\OAuth\CacheTokenProvider; |
||||
| 7 | use Commercetools\Core\Client\OAuth\ClientCredentials; |
||||
| 8 | use Commercetools\Core\Client\OAuth\CredentialTokenProvider; |
||||
| 9 | use Commercetools\Core\Client\OAuth\OAuth2Handler; |
||||
| 10 | use Commercetools\Core\Client\OAuth\TokenProvider; |
||||
| 11 | use Commercetools\Core\Config; |
||||
| 12 | use Commercetools\Core\Error\ApiException; |
||||
| 13 | use Commercetools\Core\Error\DeprecatedException; |
||||
| 14 | use Commercetools\Core\Error\InvalidTokenException; |
||||
| 15 | use Commercetools\Core\Error\Message; |
||||
| 16 | use Commercetools\Core\Helper\CorrelationIdProvider; |
||||
| 17 | use Commercetools\Core\Error\InvalidArgumentException; |
||||
| 18 | use Commercetools\Core\Model\Common\Context; |
||||
| 19 | use Commercetools\Core\Model\Common\ContextAwareInterface; |
||||
| 20 | use Commercetools\Core\Response\AbstractApiResponse; |
||||
| 21 | use GuzzleHttp\Client; |
||||
| 22 | use GuzzleHttp\Client as HttpClient; |
||||
| 23 | use GuzzleHttp\Exception\RequestException; |
||||
| 24 | use GuzzleHttp\HandlerStack; |
||||
| 25 | use GuzzleHttp\MessageFormatter; |
||||
| 26 | use GuzzleHttp\Middleware; |
||||
| 27 | use Psr\Cache\CacheItemPoolInterface; |
||||
| 28 | use Psr\Http\Message\RequestInterface; |
||||
| 29 | use Psr\Http\Message\ResponseInterface; |
||||
| 30 | use Psr\Log\LoggerInterface; |
||||
| 31 | use Psr\Log\LogLevel; |
||||
| 32 | use Psr\SimpleCache\CacheInterface; |
||||
| 33 | |||||
| 34 | /** |
||||
| 35 | * The factory to create a Client for communicating with the commercetools platform |
||||
| 36 | * |
||||
| 37 | * @description |
||||
| 38 | * This factory will create a Guzzle HTTP Client preconfigured for talking to the commercetools platform |
||||
| 39 | * |
||||
| 40 | * ## Instantiation |
||||
| 41 | * |
||||
| 42 | * ```php |
||||
| 43 | * $config = Config::fromArray( |
||||
| 44 | * ['client_id' => '<client_id>', 'client_secret' => '<client_secret>', 'project' => '<project>'] |
||||
| 45 | * ); |
||||
| 46 | * $client = ClientFactory::of()->createClient($config); |
||||
| 47 | * ``` |
||||
| 48 | * |
||||
| 49 | * ## Execution |
||||
| 50 | * |
||||
| 51 | * ### Synchronous |
||||
| 52 | * |
||||
| 53 | * ```php |
||||
| 54 | * $request = ProductProjectionSearchRequest::of(); |
||||
| 55 | * $response = $client->execute($request); |
||||
| 56 | * $products = $request->mapFromResponse($response); |
||||
| 57 | * ``` |
||||
| 58 | * |
||||
| 59 | * ### Asynchronous |
||||
| 60 | * The asynchronous execution will return a promise to fulfill the request. |
||||
| 61 | * |
||||
| 62 | * ```php |
||||
| 63 | * $request = ProductProjectionSearchRequest::of(); |
||||
| 64 | * $response = $client->executeAsync($request); |
||||
| 65 | * $products = $request->mapFromResponse($response->wait()); |
||||
| 66 | * ``` |
||||
| 67 | * |
||||
| 68 | * ### Batch |
||||
| 69 | * By filling the batch queue and starting the execution all requests will be executed in parallel. |
||||
| 70 | * |
||||
| 71 | * ```php |
||||
| 72 | * $responses = Pool::batch( |
||||
| 73 | * $client, |
||||
| 74 | * [ProductProjectionSearchRequest::of()->httpRequest(), CartByIdGetRequest::ofId($cartId)->httpRequest()] |
||||
| 75 | * ); |
||||
| 76 | * ``` |
||||
| 77 | * |
||||
| 78 | * ## Instantiation options |
||||
| 79 | * |
||||
| 80 | * ### Using a logger |
||||
| 81 | * |
||||
| 82 | * The client uses the PSR-3 logger interface for logging requests and deprecation notices. To enable |
||||
| 83 | * logging provide a PSR-3 compliant logger (e.g. Monolog). |
||||
| 84 | * |
||||
| 85 | * ```php |
||||
| 86 | * $logger = new \Monolog\Logger('name'); |
||||
| 87 | * $logger->pushHandler(new StreamHandler('./requests.log')); |
||||
| 88 | * $client = ClientFactory::of()->createClient($config, $logger); |
||||
| 89 | * ``` |
||||
| 90 | * |
||||
| 91 | * ### Using a cache adapter ### |
||||
| 92 | * |
||||
| 93 | * The client will automatically request an OAuth token and store the token in the provided cache. |
||||
| 94 | * |
||||
| 95 | * It's also possible to use a different cache adapter. The SDK provides a Doctrine, a Redis and an APCu cache adapter. |
||||
| 96 | * By default the SDK tries to instantiate the APCu or a PSR-6 filesystem cache adapter if there is no cache given. |
||||
| 97 | * E.g. Redis: |
||||
| 98 | * |
||||
| 99 | * ```php |
||||
| 100 | * $redis = new \Redis(); |
||||
| 101 | * $redis->connect('localhost'); |
||||
| 102 | * $client = ClientFactory::of()->createClient($config, null, $cache); |
||||
| 103 | * ``` |
||||
| 104 | * |
||||
| 105 | * #### Using cache and logger #### |
||||
| 106 | * |
||||
| 107 | * ```php |
||||
| 108 | * $client = ClientFactory::of()->createClient($config, $logger, $cache); |
||||
| 109 | * ``` |
||||
| 110 | * |
||||
| 111 | * #### Using a custom cache adapter #### |
||||
| 112 | * |
||||
| 113 | * ```php |
||||
| 114 | * class <CacheClass>Adapter implements \Psr\Cache\CacheItemPoolInterface { |
||||
| 115 | * protected $cache; |
||||
| 116 | * public function __construct(<CacheClass> $cache) { |
||||
| 117 | * $this->cache = $cache; |
||||
| 118 | * } |
||||
| 119 | * } |
||||
| 120 | * |
||||
| 121 | * $client->getAdapterFactory()->registerCallback(function ($cache) { |
||||
| 122 | * if ($cache instanceof <CacheClass>) { |
||||
| 123 | * return new <CacheClass>Adapter($cache); |
||||
| 124 | * } |
||||
| 125 | * return null; |
||||
| 126 | * }); |
||||
| 127 | * ``` |
||||
| 128 | * |
||||
| 129 | * ### Using a custom client class |
||||
| 130 | * |
||||
| 131 | * If some additional configuration is needed or the client should have custom logic you could provide a class name |
||||
| 132 | * to be used for the client instance. This class has to be an extended Guzzle client. |
||||
| 133 | * |
||||
| 134 | * ```php |
||||
| 135 | * $client = ClientFactory::of()->createCustomClient(MyCustomClient::class, $config); |
||||
| 136 | * ``` |
||||
| 137 | * |
||||
| 138 | * ## Middlewares |
||||
| 139 | * |
||||
| 140 | * Adding middlewares to the clients for platform as well for the authentication can be done using the config |
||||
| 141 | * by setting client options. |
||||
| 142 | * |
||||
| 143 | * ### Using a HandlerStack |
||||
| 144 | * |
||||
| 145 | * ```php |
||||
| 146 | * $handler = HandlerStack::create(); |
||||
| 147 | * $handler->push(Middleware::mapRequest(function (RequestInterface $request) { |
||||
| 148 | * ... |
||||
| 149 | * return $request; }) |
||||
| 150 | * ); |
||||
| 151 | * $config = Config::of()->setClientOptions(['handler' => $handler]) |
||||
| 152 | * ``` |
||||
| 153 | * |
||||
| 154 | * ### Using a middleware array |
||||
| 155 | * |
||||
| 156 | * ```php |
||||
| 157 | * $middlewares = [ |
||||
| 158 | * Middleware::mapRequest(function (RequestInterface $request) { |
||||
| 159 | * ... |
||||
| 160 | * return $request; }), |
||||
| 161 | * ... |
||||
| 162 | * ] |
||||
| 163 | * $config = Config::of()->setClientOptions(['middlewares' => $middlewares]) |
||||
| 164 | * ``` |
||||
| 165 | * |
||||
| 166 | * ### Timeouts |
||||
| 167 | * |
||||
| 168 | * The clients are configured to timeout by default after 60 seconds. This can be changed by setting the client options in the Config instance |
||||
| 169 | * |
||||
| 170 | * ```php |
||||
| 171 | * $config = Config::of()->setClientOptions([ |
||||
| 172 | * 'defaults' => [ |
||||
| 173 | * 'timeout' => 10 |
||||
| 174 | * ] |
||||
| 175 | * ]) |
||||
| 176 | * ``` |
||||
| 177 | * |
||||
| 178 | * Another option is to specify the timeout per request |
||||
| 179 | 28 | * |
|||
| 180 | * ```php |
||||
| 181 | 28 | * $request = ProductProjectionSearchRequest::of(); |
|||
| 182 | * $response = $client->execute($request, null, ['timeout' => 10]); |
||||
| 183 | * ``` |
||||
| 184 | 28 | * |
|||
| 185 | * ### Retrying |
||||
| 186 | * |
||||
| 187 | * As a request can error in multiple ways it's possible to add a retry middleware to the client config. E.g.: Retrying in case of service unavailable errors |
||||
| 188 | * |
||||
| 189 | * ```php |
||||
| 190 | * $config = Config::of()->setClientOptions([ |
||||
| 191 | * 'defaults' => [ |
||||
| 192 | * 'timeout' => 10 |
||||
| 193 | * ] |
||||
| 194 | * ]) |
||||
| 195 | * $maxRetries = 3; |
||||
| 196 | 27 | * $clientOptions = [ |
|||
| 197 | * 'middlewares' => [ |
||||
| 198 | * 'retry' => Middleware::retry( |
||||
| 199 | * function ($retries, RequestInterface $request, ResponseInterface $response = null, $error = null) use ($maxRetries) { |
||||
| 200 | * if ($response instanceof ResponseInterface && $response->getStatusCode() < 500) { |
||||
| 201 | * return false; |
||||
| 202 | * } |
||||
| 203 | * if ($retries > $maxRetries) { |
||||
| 204 | * return false; |
||||
| 205 | 27 | * } |
|||
| 206 | * if ($error instanceof ServiceUnavailableException) { |
||||
| 207 | 27 | * return true; |
|||
| 208 | 27 | * } |
|||
| 209 | * if ($error instanceof ServerException && $error->getCode() == 503) { |
||||
| 210 | 27 | * return true; |
|||
| 211 | 27 | * } |
|||
| 212 | 27 | * if ($response instanceof ResponseInterface && $response->getStatusCode() == 503) { |
|||
| 213 | 27 | * return true; |
|||
| 214 | * } |
||||
| 215 | * return false; |
||||
| 216 | 27 | * }, |
|||
| 217 | 27 | * [RetryMiddleware::class, 'exponentialDelay'] |
|||
| 218 | * ) |
||||
| 219 | * ] |
||||
| 220 | * ]; |
||||
| 221 | 27 | * $config->setClientOptions($clientOptions); |
|||
| 222 | 27 | * ``` |
|||
| 223 | 27 | * @package Commercetools\Core\Client |
|||
| 224 | 27 | */ |
|||
| 225 | class ClientFactory |
||||
| 226 | { |
||||
| 227 | 27 | /** |
|||
| 228 | 27 | * @var bool |
|||
| 229 | */ |
||||
| 230 | private static $isGuzzle6; |
||||
| 231 | 27 | ||||
| 232 | /** |
||||
| 233 | 27 | * ClientFactory constructor. |
|||
| 234 | 27 | * @throws DeprecatedException |
|||
| 235 | */ |
||||
| 236 | public function __construct() |
||||
| 237 | { |
||||
| 238 | 27 | if (!self::isGuzzle6()) { |
|||
| 239 | throw new DeprecatedException("ClientFactory doesn't support Guzzle version < 6"); |
||||
| 240 | } |
||||
| 241 | 27 | } |
|||
| 242 | 26 | ||||
| 243 | /** |
||||
| 244 | 27 | * @param string $clientClass |
|||
| 245 | * @param Config|array $config |
||||
| 246 | * @param LoggerInterface $logger |
||||
| 247 | * @param CacheItemPoolInterface|CacheInterface $cache |
||||
| 248 | * @param TokenProvider $provider |
||||
| 249 | * @param CacheAdapterFactory $cacheAdapterFactory |
||||
| 250 | * @param Context|null $context |
||||
| 251 | * @return Client |
||||
| 252 | */ |
||||
| 253 | public function createCustomClient( |
||||
| 254 | $clientClass, |
||||
| 255 | $config, |
||||
| 256 | 25 | LoggerInterface $logger = null, |
|||
| 257 | $cache = null, |
||||
| 258 | TokenProvider $provider = null, |
||||
| 259 | CacheAdapterFactory $cacheAdapterFactory = null, |
||||
| 260 | Context $context = null |
||||
| 261 | ) { |
||||
| 262 | $config = $this->createConfig($config); |
||||
| 263 | |||||
| 264 | 25 | if (is_null($context)) { |
|||
| 265 | 25 | $context = $config->getContext(); |
|||
| 266 | } |
||||
| 267 | if (is_null($cacheAdapterFactory)) { |
||||
| 268 | $cacheDir = $config->getCacheDir(); |
||||
| 269 | $cacheDir = !is_null($cacheDir) ? $cacheDir : realpath(__DIR__ . '/../../..'); |
||||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||||
| 270 | $cacheAdapterFactory = new CacheAdapterFactory($cacheDir); |
||||
| 271 | } |
||||
| 272 | |||||
| 273 | $cache = $cacheAdapterFactory->get($cache); |
||||
| 274 | if (is_null($cache)) { |
||||
| 275 | 14 | throw new InvalidArgumentException(Message::INVALID_CACHE_ADAPTER); |
|||
| 276 | } |
||||
| 277 | |||||
| 278 | $credentials = $config->getClientCredentials(); |
||||
| 279 | 14 | $oauthHandler = $this->getHandler( |
|||
| 280 | $credentials, |
||||
| 281 | $config->getOauthUrl(), |
||||
| 282 | 14 | $cache, |
|||
| 283 | 14 | $provider, |
|||
| 284 | $config->getOAuthClientOptions(), |
||||
| 285 | $config->getCorrelationIdProvider() |
||||
| 286 | 14 | ); |
|||
| 287 | 14 | ||||
| 288 | $options = $this->getDefaultOptions($config); |
||||
| 289 | 14 | ||||
| 290 | $client = $this->createGuzzle6Client( |
||||
| 291 | 14 | $clientClass, |
|||
| 292 | $options, |
||||
| 293 | 14 | $oauthHandler, |
|||
| 294 | $logger, |
||||
| 295 | $config->getCorrelationIdProvider() |
||||
| 296 | 27 | ); |
|||
| 297 | |||||
| 298 | 27 | if ($client instanceof ContextAwareInterface) { |
|||
| 299 | 27 | $client->setContext($context); |
|||
|
0 ignored issues
–
show
The function
GuzzleHttp\Client::__call() has been deprecated: Client::__call will be removed in guzzlehttp/guzzle:8.0.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 300 | 27 | } |
|||
| 301 | return $client; |
||||
| 302 | 27 | } |
|||
| 303 | |||||
| 304 | 27 | /** |
|||
| 305 | 27 | * @param Config|array $config |
|||
| 306 | * @param LoggerInterface $logger |
||||
| 307 | 27 | * @param CacheItemPoolInterface|CacheInterface $cache |
|||
| 308 | * @param TokenProvider $provider |
||||
| 309 | 27 | * @param CacheAdapterFactory $cacheAdapterFactory |
|||
| 310 | * @param Context|null $context |
||||
| 311 | * @return ApiClient |
||||
| 312 | */ |
||||
| 313 | public function createClient( |
||||
| 314 | $config, |
||||
| 315 | LoggerInterface $logger = null, |
||||
| 316 | $cache = null, |
||||
| 317 | 27 | TokenProvider $provider = null, |
|||
| 318 | CacheAdapterFactory $cacheAdapterFactory = null, |
||||
| 319 | 27 | Context $context = null |
|||
| 320 | 27 | ) { |
|||
| 321 | return $this->createCustomClient( |
||||
| 322 | ApiClient::class, |
||||
| 323 | $config, |
||||
| 324 | $logger, |
||||
| 325 | $cache, |
||||
| 326 | $provider, |
||||
| 327 | $cacheAdapterFactory, |
||||
| 328 | $context |
||||
| 329 | ); |
||||
| 330 | } |
||||
| 331 | |||||
| 332 | public function createAuthClient( |
||||
| 333 | array $options = [], |
||||
| 334 | CorrelationIdProvider $correlationIdProvider = null |
||||
| 335 | ) { |
||||
| 336 | 27 | if (isset($options['handler']) && $options['handler'] instanceof HandlerStack) { |
|||
| 337 | $handler = $options['handler']; |
||||
| 338 | } else { |
||||
| 339 | $handler = HandlerStack::create(); |
||||
| 340 | $options['handler'] = $handler; |
||||
| 341 | } |
||||
| 342 | |||||
| 343 | 27 | $handler->remove("http_errors"); |
|||
| 344 | $handler->unshift(self::httpErrors(), 'ctp_http_errors'); |
||||
| 345 | |||||
| 346 | 27 | $this->setCorrelationIdMiddleware($handler, $correlationIdProvider); |
|||
| 347 | 27 | ||||
| 348 | $options = $this->addMiddlewares($handler, $options); |
||||
| 349 | |||||
| 350 | 27 | return new Client($options); |
|||
| 351 | } |
||||
| 352 | 27 | ||||
| 353 | private function getDefaultOptions(Config $config) |
||||
| 354 | { |
||||
| 355 | $options = $config->getClientOptions(); |
||||
| 356 | $options['http_errors'] = $config->getThrowExceptions(); |
||||
| 357 | $options['base_uri'] = $config->getApiUrl() . "/" . $config->getProject() . "/"; |
||||
| 358 | $defaultHeaders = [ |
||||
| 359 | 'User-Agent' => (new UserAgentProvider())->getUserAgent() |
||||
| 360 | ]; |
||||
| 361 | 27 | if (!is_null($config->getAcceptEncoding())) { |
|||
|
0 ignored issues
–
show
|
|||||
| 362 | 23 | $defaultHeaders['Accept-Encoding'] = $config->getAcceptEncoding(); |
|||
| 363 | } |
||||
| 364 | $options['headers'] = array_merge($defaultHeaders, (isset($options['headers']) ? $options['headers'] : [])); |
||||
| 365 | 27 | ||||
| 366 | 27 | return $options; |
|||
| 367 | } |
||||
| 368 | 27 | ||||
| 369 | 27 | /** |
|||
| 370 | 27 | * @param Config|array $config |
|||
| 371 | * @return Config |
||||
| 372 | 27 | * @throws InvalidArgumentException |
|||
| 373 | 26 | */ |
|||
| 374 | 26 | private function createConfig($config) |
|||
| 375 | 26 | { |
|||
| 376 | if ($config instanceof Config) { |
||||
| 377 | return $config; |
||||
| 378 | } |
||||
| 379 | 27 | if (is_array($config)) { |
|||
|
0 ignored issues
–
show
|
|||||
| 380 | 27 | return Config::fromArray($config); |
|||
| 381 | } |
||||
| 382 | 27 | throw new InvalidArgumentException(); |
|||
| 383 | } |
||||
| 384 | 27 | ||||
| 385 | /** |
||||
| 386 | * @param string $clientClass |
||||
| 387 | 23 | * @param array $options |
|||
| 388 | * @param OAuth2Handler $oauthHandler |
||||
| 389 | * @param LoggerInterface|null $logger |
||||
| 390 | * @param CorrelationIdProvider|null $correlationIdProvider |
||||
| 391 | * @return Client |
||||
| 392 | */ |
||||
| 393 | 23 | private function createGuzzle6Client( |
|||
| 394 | 23 | $clientClass, |
|||
| 395 | array $options, |
||||
| 396 | 23 | OAuth2Handler $oauthHandler, |
|||
| 397 | 23 | LoggerInterface $logger = null, |
|||
| 398 | CorrelationIdProvider $correlationIdProvider = null |
||||
| 399 | ) { |
||||
| 400 | if (isset($options['handler']) && $options['handler'] instanceof HandlerStack) { |
||||
| 401 | $handler = $options['handler']; |
||||
| 402 | } else { |
||||
| 403 | 704 | $handler = HandlerStack::create(); |
|||
| 404 | $options['handler'] = $handler; |
||||
| 405 | } |
||||
| 406 | |||||
| 407 | 27 | $options = array_merge( |
|||
| 408 | 704 | [ |
|||
| 409 | 702 | 'allow_redirects' => false, |
|||
| 410 | 702 | 'verify' => true, |
|||
| 411 | 702 | 'timeout' => 60, |
|||
| 412 | 'connect_timeout' => 10, |
||||
| 413 | 27 | 'pool_size' => 25, |
|||
| 414 | ], |
||||
| 415 | 27 | $options |
|||
| 416 | ); |
||||
| 417 | |||||
| 418 | if (!is_null($logger)) { |
||||
| 419 | $this->setLogger($handler, $logger); |
||||
| 420 | } |
||||
| 421 | |||||
| 422 | 27 | $handler->remove("http_errors"); |
|||
| 423 | $handler->unshift(self::httpErrors(), 'ctp_http_errors'); |
||||
| 424 | 27 | ||||
| 425 | 4 | $handler->push( |
|||
| 426 | 4 | Middleware::mapRequest($oauthHandler), |
|||
| 427 | 4 | 'oauth_2_0' |
|||
| 428 | 4 | ); |
|||
| 429 | 4 | if ($oauthHandler->refreshable()) { |
|||
| 430 | $handler->push( |
||||
| 431 | self::reauthenticate($oauthHandler), |
||||
| 432 | 'reauthenticate' |
||||
| 433 | ); |
||||
| 434 | } |
||||
| 435 | |||||
| 436 | 27 | $this->setCorrelationIdMiddleware($handler, $correlationIdProvider); |
|||
| 437 | $options = $this->addMiddlewares($handler, $options); |
||||
| 438 | |||||
| 439 | $client = new $clientClass($options); |
||||
| 440 | |||||
| 441 | return $client; |
||||
| 442 | } |
||||
| 443 | |||||
| 444 | private function setLogger( |
||||
| 445 | HandlerStack $handler, |
||||
| 446 | 701 | LoggerInterface $logger, |
|||
| 447 | $logLevel = LogLevel::INFO, |
||||
| 448 | 26 | $formatter = null |
|||
| 449 | 701 | ) { |
|||
| 450 | 700 | if (is_null($formatter)) { |
|||
| 451 | 700 | $formatter = new MessageFormatter(); |
|||
| 452 | 700 | } |
|||
| 453 | 700 | $handler->push(self::log($logger, $formatter, $logLevel), 'ctp_logger'); |
|||
| 454 | 700 | } |
|||
| 455 | 700 | ||||
| 456 | 700 | /** |
|||
| 457 | * @param CorrelationIdProvider $correlationIdProvider |
||||
| 458 | 700 | * @param HandlerStack $handler |
|||
| 459 | 1 | */ |
|||
| 460 | 1 | private function setCorrelationIdMiddleware( |
|||
| 461 | HandlerStack $handler, |
||||
| 462 | 1 | CorrelationIdProvider $correlationIdProvider = null |
|||
| 463 | 1 | ) { |
|||
| 464 | 1 | if (!is_null($correlationIdProvider)) { |
|||
| 465 | 1 | $handler->push(Middleware::mapRequest(function (RequestInterface $request) use ($correlationIdProvider) { |
|||
| 466 | 1 | return $request->withAddedHeader( |
|||
| 467 | 1 | AbstractApiResponse::X_CORRELATION_ID, |
|||
| 468 | 1 | $correlationIdProvider->getCorrelationId() |
|||
| 469 | ); |
||||
| 470 | 1 | }), 'ctp_correlation_id'); |
|||
| 471 | } |
||||
| 472 | } |
||||
| 473 | 699 | ||||
| 474 | 700 | /** |
|||
| 475 | * @param HandlerStack $handler |
||||
| 476 | 24 | * @param array $options |
|||
| 477 | 26 | * @return array |
|||
| 478 | */ |
||||
| 479 | private function addMiddlewares(HandlerStack $handler, array $options) |
||||
| 480 | { |
||||
| 481 | if (isset($options['middlewares']) && is_array($options['middlewares'])) { |
||||
| 482 | foreach ($options['middlewares'] as $key => $middleware) { |
||||
| 483 | if (is_callable($middleware)) { |
||||
| 484 | if (!is_numeric($key)) { |
||||
| 485 | $handler->remove($key); |
||||
| 486 | 702 | $handler->push($middleware, $key); |
|||
| 487 | } else { |
||||
| 488 | 27 | $handler->push($middleware); |
|||
| 489 | 702 | } |
|||
| 490 | 702 | } |
|||
| 491 | 20 | } |
|||
| 492 | } |
||||
| 493 | 684 | return $options; |
|||
| 494 | 684 | } |
|||
| 495 | 684 | ||||
| 496 | 684 | /** |
|||
| 497 | 674 | * Middleware that reauthenticates on invalid token error |
|||
| 498 | * |
||||
| 499 | 214 | * @param OAuth2Handler $oauthHandler |
|||
| 500 | 684 | * @param int $maxRetries |
|||
| 501 | * @return callable Returns a function that accepts the next handler. |
||||
| 502 | 25 | */ |
|||
| 503 | 27 | public static function reauthenticate(OAuth2Handler $oauthHandler, $maxRetries = 1) |
|||
| 504 | { |
||||
| 505 | return function (callable $handler) use ($oauthHandler, $maxRetries) { |
||||
| 506 | return function (RequestInterface $request, array $options) use ($handler, $oauthHandler, $maxRetries) { |
||||
| 507 | return $handler($request, $options)->then( |
||||
| 508 | function (ResponseInterface $response) use ( |
||||
| 509 | $request, |
||||
| 510 | $handler, |
||||
| 511 | $oauthHandler, |
||||
| 512 | $options, |
||||
| 513 | $maxRetries |
||||
| 514 | ) { |
||||
| 515 | 27 | if ($response->getStatusCode() == 401) { |
|||
| 516 | if (!isset($options['reauth'])) { |
||||
| 517 | $options['reauth'] = 0; |
||||
| 518 | } |
||||
| 519 | $exception = ApiException::create($request, $response); |
||||
| 520 | if ($options['reauth'] < $maxRetries && $exception instanceof InvalidTokenException) { |
||||
| 521 | $options['reauth']++; |
||||
| 522 | $token = $oauthHandler->refreshToken(); |
||||
| 523 | 27 | $request = $request->withHeader( |
|||
| 524 | 14 | 'Authorization', |
|||
| 525 | 14 | 'Bearer ' . $token->getToken() |
|||
| 526 | ); |
||||
| 527 | return $handler($request, $options); |
||||
| 528 | } |
||||
| 529 | 14 | } |
|||
| 530 | 14 | return $response; |
|||
| 531 | } |
||||
| 532 | 27 | ); |
|||
| 533 | }; |
||||
| 534 | }; |
||||
| 535 | } |
||||
| 536 | |||||
| 537 | /** |
||||
| 538 | * Middleware that throws exceptions for 4xx or 5xx responses when the |
||||
| 539 | * "http_error" request option is set to true. |
||||
| 540 | * |
||||
| 541 | * @return callable Returns a function that accepts the next handler. |
||||
| 542 | */ |
||||
| 543 | public static function httpErrors() |
||||
| 544 | { |
||||
| 545 | 700 | return function (callable $handler) { |
|||
| 546 | return function ($request, array $options) use ($handler) { |
||||
| 547 | 23 | if (empty($options['http_errors'])) { |
|||
| 548 | 700 | return $handler($request, $options); |
|||
| 549 | 700 | } |
|||
| 550 | 700 | return $handler($request, $options)->then( |
|||
| 551 | 700 | function (ResponseInterface $response) use ($request, $handler) { |
|||
|
0 ignored issues
–
show
|
|||||
| 552 | $code = $response->getStatusCode(); |
||||
| 553 | 700 | if ($code < 400) { |
|||
| 554 | 700 | return $response; |
|||
| 555 | } |
||||
| 556 | throw ApiException::create($request, $response); |
||||
| 557 | 700 | } |
|||
| 558 | 700 | ); |
|||
| 559 | 700 | }; |
|||
| 560 | 700 | }; |
|||
| 561 | } |
||||
| 562 | |||||
| 563 | /** |
||||
| 564 | * @param ClientCredentials $credentials |
||||
| 565 | * @param string $accessTokenUrl |
||||
| 566 | * @param CacheItemPoolInterface|CacheInterface $cache |
||||
| 567 | * @param TokenProvider $provider |
||||
| 568 | * @param array $authClientOptions |
||||
| 569 | * @param CorrelationIdProvider|null $correlationIdProvider |
||||
| 570 | * @return OAuth2Handler |
||||
| 571 | */ |
||||
| 572 | private function getHandler( |
||||
| 573 | ClientCredentials $credentials, |
||||
| 574 | 700 | $accessTokenUrl, |
|||
| 575 | $cache, |
||||
| 576 | 23 | TokenProvider $provider = null, |
|||
| 577 | 23 | array $authClientOptions = [], |
|||
| 578 | CorrelationIdProvider $correlationIdProvider = null |
||||
| 579 | ) { |
||||
| 580 | if (is_null($provider)) { |
||||
| 581 | $provider = new CredentialTokenProvider( |
||||
| 582 | $this->createAuthClient($authClientOptions, $correlationIdProvider), |
||||
| 583 | 28 | $accessTokenUrl, |
|||
| 584 | $credentials |
||||
| 585 | 28 | ); |
|||
| 586 | 1 | $cacheKey = sha1($credentials->getClientId() . $credentials->getScope()); |
|||
| 587 | 1 | $provider = new CacheTokenProvider($provider, $cache, $cacheKey); |
|||
| 588 | } |
||||
| 589 | return new OAuth2Handler($provider); |
||||
| 590 | } |
||||
| 591 | 1 | ||||
| 592 | 1 | /** |
|||
| 593 | * Middleware that logs requests, responses, and errors using a message |
||||
| 594 | * formatter. |
||||
| 595 | * |
||||
| 596 | * @param LoggerInterface $logger Logs messages. |
||||
| 597 | 28 | * @param MessageFormatter $formatter Formatter used to create message strings. |
|||
| 598 | * @param string $logLevel Level at which to log requests. |
||||
| 599 | * |
||||
| 600 | * @return callable Returns a function that accepts the next handler. |
||||
| 601 | */ |
||||
| 602 | private static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO) |
||||
| 603 | 28 | { |
|||
| 604 | return function (callable $handler) use ($logger, $formatter, $logLevel) { |
||||
| 605 | 28 | return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) { |
|||
| 606 | return $handler($request, $options)->then( |
||||
| 607 | function (ResponseInterface $response) use ($logger, $request, $formatter, $logLevel) { |
||||
| 608 | $message = $formatter->format($request, $response); |
||||
| 609 | $context = [ |
||||
| 610 | AbstractApiResponse::X_CORRELATION_ID => $response->getHeader( |
||||
| 611 | AbstractApiResponse::X_CORRELATION_ID |
||||
| 612 | ) |
||||
| 613 | ]; |
||||
| 614 | $logger->log($logLevel, $message, $context); |
||||
| 615 | return $response; |
||||
| 616 | }, |
||||
| 617 | function ($reason) use ($logger, $request, $formatter) { |
||||
| 618 | $response = null; |
||||
| 619 | $context = []; |
||||
| 620 | if ($reason instanceof RequestException) { |
||||
| 621 | $response = $reason->getResponse(); |
||||
| 622 | if (!is_null($response)) { |
||||
| 623 | $context[AbstractApiResponse::X_CORRELATION_ID] = $response->getHeader( |
||||
| 624 | AbstractApiResponse::X_CORRELATION_ID |
||||
| 625 | ); |
||||
| 626 | } |
||||
| 627 | } |
||||
| 628 | $message = $formatter->format($request, $response, $reason); |
||||
| 629 | $logger->notice($message, $context); |
||||
| 630 | return \GuzzleHttp\Promise\rejection_for($reason); |
||||
|
0 ignored issues
–
show
The function
GuzzleHttp\Promise\rejection_for() has been deprecated: rejection_for will be removed in guzzlehttp/promises:2.0. Use Create::rejectionFor instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 631 | } |
||||
| 632 | ); |
||||
| 633 | }; |
||||
| 634 | }; |
||||
| 635 | } |
||||
| 636 | |||||
| 637 | /** |
||||
| 638 | * @return bool |
||||
| 639 | */ |
||||
| 640 | private static function isGuzzle6() |
||||
| 641 | { |
||||
| 642 | if (is_null(self::$isGuzzle6)) { |
||||
|
0 ignored issues
–
show
|
|||||
| 643 | if (defined('\GuzzleHttp\Client::MAJOR_VERSION')) { |
||||
| 644 | $clientVersion = (string) constant(HttpClient::class . '::MAJOR_VERSION'); |
||||
| 645 | } else { |
||||
| 646 | $clientVersion = (string) constant(HttpClient::class . '::VERSION'); |
||||
| 647 | } |
||||
| 648 | if (version_compare($clientVersion, '6.0.0', '>=')) { |
||||
| 649 | self::$isGuzzle6 = true; |
||||
| 650 | } else { |
||||
| 651 | self::$isGuzzle6 = false; |
||||
| 652 | } |
||||
| 653 | } |
||||
| 654 | return self::$isGuzzle6; |
||||
| 655 | } |
||||
| 656 | |||||
| 657 | /** |
||||
| 658 | * @return ClientFactory |
||||
| 659 | */ |
||||
| 660 | public static function of() |
||||
| 661 | { |
||||
| 662 | return new static(); |
||||
| 663 | } |
||||
| 664 | } |
||||
| 665 |