1: <?php
2: namespace Worldline\Connect\Sdk;
3:
4: use Exception;
5: use UnexpectedValueException;
6: use Worldline\Connect\Sdk\Authentication\Authenticator;
7: use Worldline\Connect\Sdk\Authentication\V1HMACAuthenticator;
8: use Worldline\Connect\Sdk\Communication\Connection;
9: use Worldline\Connect\Sdk\Communication\ConnectionResponse;
10: use Worldline\Connect\Sdk\Communication\DefaultConnection;
11: use Worldline\Connect\Sdk\Communication\ErrorResponseException;
12: use Worldline\Connect\Sdk\Communication\MetadataProvider;
13: use Worldline\Connect\Sdk\Communication\MultipartDataObject;
14: use Worldline\Connect\Sdk\Communication\MultipartFormDataObject;
15: use Worldline\Connect\Sdk\Communication\RequestObject;
16: use Worldline\Connect\Sdk\Communication\ResponseBuilder;
17: use Worldline\Connect\Sdk\Communication\ResponseClassMap;
18: use Worldline\Connect\Sdk\Communication\ResponseFactory;
19: use Worldline\Connect\Sdk\Domain\DataObject;
20: use Worldline\Connect\Sdk\Logging\CommunicatorLogger;
21:
22: /**
23: * Class Communicator
24: *
25: * @package Worldline\Connect\Sdk
26: */
27: class Communicator
28: {
29: const MIME_APPLICATION_JSON = 'application/json';
30:
31: /**
32: * @var string
33: */
34: private string $apiEndpoint;
35:
36: /**
37: * @var Authenticator
38: */
39: private Authenticator $authenticator;
40:
41: /**
42: * @var Connection
43: */
44: private Connection $connection;
45:
46: /**
47: * @var MetadataProvider
48: */
49: private MetadataProvider $metadataProvider;
50:
51: /**
52: * @var ResponseFactory|null
53: */
54: private ?ResponseFactory $responseFactory = null;
55:
56: /**
57: * @param CommunicatorConfiguration $communicatorConfiguration
58: * @param Authenticator|null $authenticator
59: * @param Connection|null $connection
60: */
61: public function __construct(
62: CommunicatorConfiguration $communicatorConfiguration,
63: ?Authenticator $authenticator = null,
64: ?Connection $connection = null
65: ) {
66: $this->apiEndpoint = $communicatorConfiguration->getApiEndpoint();
67: $this->authenticator = $authenticator != null ? $authenticator : new V1HMACAuthenticator($communicatorConfiguration);
68: $this->connection = $connection != null ? $connection : new DefaultConnection($communicatorConfiguration);
69: $this->metadataProvider = new MetadataProvider($communicatorConfiguration);
70: }
71:
72: /**
73: * @param CommunicatorLogger $communicatorLogger
74: *
75: * @return void
76: */
77: public function enableLogging(CommunicatorLogger $communicatorLogger): void
78: {
79: $this->connection->enableLogging($communicatorLogger);
80: }
81:
82: /**
83: * @return void
84: */
85: public function disableLogging(): void
86: {
87: $this->connection->disableLogging();
88: }
89:
90: /**
91: * @param ResponseClassMap $responseClassMap
92: * @param string $relativeUriPath
93: * @param string $clientMetaInfo
94: * @param RequestObject|null $requestParameters
95: * @param CallContext|null $callContext
96: *
97: * @return DataObject|null
98: * @throws Exception
99: */
100: public function get(
101: ResponseClassMap $responseClassMap,
102: string $relativeUriPath,
103: string $clientMetaInfo = '',
104: ?RequestObject $requestParameters = null,
105: ?CallContext $callContext = null
106: ): ?DataObject {
107: $relativeUriPathWithRequestParameters = $this->getRelativeUriPathWithRequestParameters($relativeUriPath, $requestParameters);
108: $requestHeaders = $this->getRequestHeaders('GET', $relativeUriPathWithRequestParameters, null, $clientMetaInfo, $callContext);
109:
110: $responseBuilder = new ResponseBuilder();
111: $responseHandler = function ($httpStatusCode, $data, $headers) use ($responseBuilder) {
112: $responseBuilder->setHttpStatusCode($httpStatusCode);
113: $responseBuilder->setHeaders($headers);
114: $responseBuilder->appendBody($data);
115: };
116:
117: $this->connection->get(
118: $this->apiEndpoint . $relativeUriPathWithRequestParameters,
119: $requestHeaders,
120: $responseHandler
121: );
122: $connectionResponse = $responseBuilder->getResponse();
123: $this->updateCallContext($connectionResponse, $callContext);
124: $response = $this->getResponseFactory()->createResponse($connectionResponse, $responseClassMap);
125: $httpStatusCode = $connectionResponse->getHttpStatusCode();
126: if ($httpStatusCode >= 400) {
127: throw new ErrorResponseException($httpStatusCode, $response);
128: }
129: return $response;
130: }
131:
132: /**
133: * @param callable $bodyHandler Callable accepting a response body chunk and the response headers
134: * @param ResponseClassMap $responseClassMap Used for error handling
135: * @param string $relativeUriPath
136: * @param string $clientMetaInfo
137: * @param RequestObject|null $requestParameters
138: * @param CallContext|null $callContext
139: *
140: * @return void
141: * @throws Exception
142: */
143: public function getWithBinaryResponse(
144: callable $bodyHandler,
145: ResponseClassMap $responseClassMap,
146: string $relativeUriPath,
147: string $clientMetaInfo = '',
148: ?RequestObject $requestParameters = null,
149: ?CallContext $callContext = null
150: ): void {
151: $relativeUriPathWithRequestParameters = $this->getRelativeUriPathWithRequestParameters($relativeUriPath, $requestParameters);
152: $requestHeaders = $this->getRequestHeaders('GET', $relativeUriPathWithRequestParameters, null, $clientMetaInfo, $callContext);
153:
154: $responseBuilder = new ResponseBuilder();
155: $responseHandler = function ($httpStatusCode, $data, $headers) use ($responseBuilder, $bodyHandler) {
156: $responseBuilder->setHttpStatusCode($httpStatusCode);
157: $responseBuilder->setHeaders($headers);
158: if ($httpStatusCode >= 400) {
159: $responseBuilder->appendBody($data);
160: } else {
161: call_user_func($bodyHandler, $data, $headers);
162: }
163: };
164:
165: $this->connection->get(
166: $this->apiEndpoint . $relativeUriPathWithRequestParameters,
167: $requestHeaders,
168: $responseHandler
169: );
170: $connectionResponse = $responseBuilder->getResponse();
171: $this->updateCallContext($connectionResponse, $callContext);
172: $httpStatusCode = $connectionResponse->getHttpStatusCode();
173: if ($httpStatusCode >= 400) {
174: $response = $this->getResponseFactory()->createResponse($connectionResponse, $responseClassMap);
175: throw new ErrorResponseException($httpStatusCode, $response);
176: }
177: }
178:
179: /**
180: * @param ResponseClassMap $responseClassMap
181: * @param string $relativeUriPath
182: * @param string $clientMetaInfo
183: * @param RequestObject|null $requestParameters
184: * @param CallContext|null $callContext
185: *
186: * @return DataObject|null
187: * @throws Exception
188: */
189: public function delete(
190: ResponseClassMap $responseClassMap,
191: string $relativeUriPath,
192: string $clientMetaInfo = '',
193: ?RequestObject $requestParameters = null,
194: ?CallContext $callContext = null
195: ): ?DataObject {
196: $relativeUriPathWithRequestParameters = $this->getRelativeUriPathWithRequestParameters($relativeUriPath, $requestParameters);
197: $requestHeaders = $this->getRequestHeaders('DELETE', $relativeUriPathWithRequestParameters, null, $clientMetaInfo, $callContext);
198:
199: $responseBuilder = new ResponseBuilder();
200: $responseHandler = function ($httpStatusCode, $data, $headers) use ($responseBuilder) {
201: $responseBuilder->setHttpStatusCode($httpStatusCode);
202: $responseBuilder->setHeaders($headers);
203: $responseBuilder->appendBody($data);
204: };
205:
206: $this->connection->delete(
207: $this->apiEndpoint . $relativeUriPathWithRequestParameters,
208: $requestHeaders,
209: $responseHandler
210: );
211: $connectionResponse = $responseBuilder->getResponse();
212: $this->updateCallContext($connectionResponse, $callContext);
213: $response = $this->getResponseFactory()->createResponse($connectionResponse, $responseClassMap);
214: $httpStatusCode = $connectionResponse->getHttpStatusCode();
215: if ($httpStatusCode >= 400) {
216: throw new ErrorResponseException($httpStatusCode, $response);
217: }
218: return $response;
219: }
220:
221: /**
222: * @param callable $bodyHandler Callable accepting a response body chunk and the response headers
223: * @param ResponseClassMap $responseClassMap Used for error handling
224: * @param string $relativeUriPath
225: * @param string $clientMetaInfo
226: * @param RequestObject|null $requestParameters
227: * @param CallContext|null $callContext
228: *
229: * @return void
230: * @throws Exception
231: */
232: public function deleteWithBinaryResponse(
233: callable $bodyHandler,
234: ResponseClassMap $responseClassMap,
235: string $relativeUriPath,
236: string $clientMetaInfo = '',
237: ?RequestObject $requestParameters = null,
238: ?CallContext $callContext = null
239: ): void {
240: $relativeUriPathWithRequestParameters = $this->getRelativeUriPathWithRequestParameters($relativeUriPath, $requestParameters);
241: $requestHeaders = $this->getRequestHeaders('DELETE', $relativeUriPathWithRequestParameters, null, $clientMetaInfo, $callContext);
242:
243: $responseBuilder = new ResponseBuilder();
244: $responseHandler = function ($httpStatusCode, $data, $headers) use ($responseBuilder, $bodyHandler) {
245: $responseBuilder->setHttpStatusCode($httpStatusCode);
246: $responseBuilder->setHeaders($headers);
247: if ($httpStatusCode >= 400) {
248: $responseBuilder->appendBody($data);
249: } else {
250: call_user_func($bodyHandler, $data, $headers);
251: }
252: };
253:
254: $this->connection->delete(
255: $this->apiEndpoint . $relativeUriPathWithRequestParameters,
256: $requestHeaders,
257: $responseHandler
258: );
259: $connectionResponse = $responseBuilder->getResponse();
260: $this->updateCallContext($connectionResponse, $callContext);
261: $httpStatusCode = $connectionResponse->getHttpStatusCode();
262: if ($httpStatusCode >= 400) {
263: $response = $this->getResponseFactory()->createResponse($connectionResponse, $responseClassMap);
264: throw new ErrorResponseException($httpStatusCode, $response);
265: }
266: }
267:
268: /**
269: * @param ResponseClassMap $responseClassMap
270: * @param string $relativeUriPath
271: * @param string $clientMetaInfo
272: * @param DataObject|MultipartDataObject|MultipartFormDataObject|null $requestBodyObject
273: * @param RequestObject|null $requestParameters
274: * @param CallContext|null $callContext
275: *
276: * @return DataObject|null
277: * @throws Exception
278: */
279: public function post(
280: ResponseClassMap $responseClassMap,
281: string $relativeUriPath,
282: string $clientMetaInfo = '',
283: $requestBodyObject = null,
284: ?RequestObject $requestParameters = null,
285: ?CallContext $callContext = null
286: ): ?DataObject {
287: $relativeUriPathWithRequestParameters = $this->getRelativeUriPathWithRequestParameters($relativeUriPath, $requestParameters);
288: if ($requestBodyObject instanceof MultipartFormDataObject) {
289: $contentType = $requestBodyObject->getContentType();
290: $requestBody = $requestBodyObject;
291: } elseif ($requestBodyObject instanceof MultipartDataObject) {
292: $multipart = $requestBodyObject->toMultipartFormDataObject();
293: $contentType = $multipart->getContentType();
294: $requestBody = $multipart;
295: } elseif ($requestBodyObject instanceof DataObject || is_null($requestBodyObject)) {
296: $contentType = static::MIME_APPLICATION_JSON;
297: $requestBody = $requestBodyObject ? $requestBodyObject->toJson() : '';
298: } else {
299: throw new UnexpectedValueException('Unsupported request body');
300: }
301: $requestHeaders = $this->getRequestHeaders('POST', $relativeUriPathWithRequestParameters, $contentType, $clientMetaInfo, $callContext);
302:
303: $responseBuilder = new ResponseBuilder();
304: $responseHandler = function ($httpStatusCode, $data, $headers) use ($responseBuilder) {
305: $responseBuilder->setHttpStatusCode($httpStatusCode);
306: $responseBuilder->setHeaders($headers);
307: $responseBuilder->appendBody($data);
308: };
309:
310: $this->connection->post(
311: $this->apiEndpoint . $relativeUriPathWithRequestParameters,
312: $requestHeaders,
313: $requestBody,
314: $responseHandler
315: );
316: $connectionResponse = $responseBuilder->getResponse();
317: $this->updateCallContext($connectionResponse, $callContext);
318: $response = $this->getResponseFactory()->createResponse($connectionResponse, $responseClassMap);
319: $httpStatusCode = $connectionResponse->getHttpStatusCode();
320: if ($httpStatusCode >= 400) {
321: throw new ErrorResponseException($httpStatusCode, $response);
322: }
323: return $response;
324: }
325:
326: /**
327: * @param callable $bodyHandler Callable accepting a response body chunk
328: * and the response headers
329: * @param ResponseClassMap $responseClassMap Used for error handling
330: * @param string $relativeUriPath
331: * @param string $clientMetaInfo
332: * @param DataObject|MultipartDataObject|MultipartFormDataObject|null $requestBodyObject
333: * @param RequestObject|null $requestParameters
334: * @param CallContext|null $callContext
335: *
336: * @return void
337: * @throws Exception
338: */
339: public function postWithBinaryResponse(
340: callable $bodyHandler,
341: ResponseClassMap $responseClassMap,
342: string $relativeUriPath,
343: string $clientMetaInfo = '',
344: $requestBodyObject = null,
345: ?RequestObject $requestParameters = null,
346: ?CallContext $callContext = null
347: ): void {
348: $relativeUriPathWithRequestParameters = $this->getRelativeUriPathWithRequestParameters($relativeUriPath, $requestParameters);
349: if ($requestBodyObject instanceof MultipartFormDataObject) {
350: $contentType = $requestBodyObject->getContentType();
351: $requestBody = $requestBodyObject;
352: } elseif ($requestBodyObject instanceof MultipartDataObject) {
353: $multipart = $requestBodyObject->toMultipartFormDataObject();
354: $contentType = $multipart->getContentType();
355: $requestBody = $multipart;
356: } elseif ($requestBodyObject instanceof DataObject || is_null($requestBodyObject)) {
357: $contentType = static::MIME_APPLICATION_JSON;
358: $requestBody = $requestBodyObject ? $requestBodyObject->toJson() : '';
359: } else {
360: throw new UnexpectedValueException('Unsupported request body');
361: }
362: $requestHeaders = $this->getRequestHeaders('POST', $relativeUriPathWithRequestParameters, $contentType, $clientMetaInfo, $callContext);
363:
364: $responseBuilder = new ResponseBuilder();
365: $responseHandler = function ($httpStatusCode, $data, $headers) use ($responseBuilder, $bodyHandler) {
366: $responseBuilder->setHttpStatusCode($httpStatusCode);
367: $responseBuilder->setHeaders($headers);
368: if ($httpStatusCode >= 400) {
369: $responseBuilder->appendBody($data);
370: } else {
371: call_user_func($bodyHandler, $data, $headers);
372: }
373: };
374:
375: $this->connection->post(
376: $this->apiEndpoint . $relativeUriPathWithRequestParameters,
377: $requestHeaders,
378: $requestBody,
379: $responseHandler
380: );
381: $connectionResponse = $responseBuilder->getResponse();
382: $this->updateCallContext($connectionResponse, $callContext);
383: $httpStatusCode = $connectionResponse->getHttpStatusCode();
384: if ($httpStatusCode >= 400) {
385: $response = $this->getResponseFactory()->createResponse($connectionResponse, $responseClassMap);
386: throw new ErrorResponseException($httpStatusCode, $response);
387: }
388: }
389:
390: /**
391: * @param ResponseClassMap $responseClassMap
392: * @param string $relativeUriPath
393: * @param string $clientMetaInfo
394: * @param DataObject|MultipartDataObject|MultipartFormDataObject|null $requestBodyObject
395: * @param RequestObject|null $requestParameters
396: * @param CallContext|null $callContext
397: *
398: * @return DataObject|null
399: * @throws Exception
400: */
401: public function put(
402: ResponseClassMap $responseClassMap,
403: string $relativeUriPath,
404: string $clientMetaInfo = '',
405: $requestBodyObject = null,
406: ?RequestObject $requestParameters = null,
407: ?CallContext $callContext = null
408: ): ?DataObject {
409: $relativeUriPathWithRequestParameters = $this->getRelativeUriPathWithRequestParameters($relativeUriPath, $requestParameters);
410: if ($requestBodyObject instanceof MultipartFormDataObject) {
411: $contentType = $requestBodyObject->getContentType();
412: $requestBody = $requestBodyObject;
413: } elseif ($requestBodyObject instanceof MultipartDataObject) {
414: $multipart = $requestBodyObject->toMultipartFormDataObject();
415: $contentType = $multipart->getContentType();
416: $requestBody = $multipart;
417: } elseif ($requestBodyObject instanceof DataObject || is_null($requestBodyObject)) {
418: $contentType = static::MIME_APPLICATION_JSON;
419: $requestBody = $requestBodyObject ? $requestBodyObject->toJson() : '';
420: } else {
421: throw new UnexpectedValueException('Unsupported request body');
422: }
423: $requestHeaders = $this->getRequestHeaders('PUT', $relativeUriPathWithRequestParameters, $contentType, $clientMetaInfo, $callContext);
424:
425: $responseBuilder = new ResponseBuilder();
426: $responseHandler = function ($httpStatusCode, $data, $headers) use ($responseBuilder) {
427: $responseBuilder->setHttpStatusCode($httpStatusCode);
428: $responseBuilder->setHeaders($headers);
429: $responseBuilder->appendBody($data);
430: };
431:
432: $this->connection->put(
433: $this->apiEndpoint . $relativeUriPathWithRequestParameters,
434: $requestHeaders,
435: $requestBody,
436: $responseHandler
437: );
438: $connectionResponse = $responseBuilder->getResponse();
439: $this->updateCallContext($connectionResponse, $callContext);
440: $response = $this->getResponseFactory()->createResponse($connectionResponse, $responseClassMap);
441: $httpStatusCode = $connectionResponse->getHttpStatusCode();
442: if ($httpStatusCode >= 400) {
443: throw new ErrorResponseException($httpStatusCode, $response);
444: }
445: return $response;
446: }
447:
448: /**
449: * @param callable $bodyHandler Callable accepting a response body chunk
450: * and the response headers
451: * @param ResponseClassMap $responseClassMap Used for error handling
452: * @param string $relativeUriPath
453: * @param string $clientMetaInfo
454: * @param DataObject|MultipartDataObject|MultipartFormDataObject|null $requestBodyObject
455: * @param RequestObject|null $requestParameters
456: * @param CallContext|null $callContext
457: *
458: * @return void
459: * @throws Exception
460: */
461: public function putWithBinaryResponse(
462: callable $bodyHandler,
463: ResponseClassMap $responseClassMap,
464: string $relativeUriPath,
465: string $clientMetaInfo = '',
466: $requestBodyObject = null,
467: ?RequestObject $requestParameters = null,
468: ?CallContext $callContext = null
469: ): void {
470: $relativeUriPathWithRequestParameters = $this->getRelativeUriPathWithRequestParameters($relativeUriPath, $requestParameters);
471: if ($requestBodyObject instanceof MultipartFormDataObject) {
472: $contentType = $requestBodyObject->getContentType();
473: $requestBody = $requestBodyObject;
474: } elseif ($requestBodyObject instanceof MultipartDataObject) {
475: $multipart = $requestBodyObject->toMultipartFormDataObject();
476: $contentType = $multipart->getContentType();
477: $requestBody = $multipart;
478: } elseif ($requestBodyObject instanceof DataObject || is_null($requestBodyObject)) {
479: $contentType = static::MIME_APPLICATION_JSON;
480: $requestBody = $requestBodyObject ? $requestBodyObject->toJson() : '';
481: } else {
482: throw new UnexpectedValueException('Unsupported request body');
483: }
484: $requestHeaders = $this->getRequestHeaders('PUT', $relativeUriPathWithRequestParameters, $contentType, $clientMetaInfo, $callContext);
485:
486: $responseBuilder = new ResponseBuilder();
487: $responseHandler = function ($httpStatusCode, $data, $headers) use ($responseBuilder, $bodyHandler) {
488: $responseBuilder->setHttpStatusCode($httpStatusCode);
489: $responseBuilder->setHeaders($headers);
490: if ($httpStatusCode >= 400) {
491: $responseBuilder->appendBody($data);
492: } else {
493: call_user_func($bodyHandler, $data, $headers);
494: }
495: };
496:
497: $this->connection->put(
498: $this->apiEndpoint . $relativeUriPathWithRequestParameters,
499: $requestHeaders,
500: $requestBody,
501: $responseHandler
502: );
503: $connectionResponse = $responseBuilder->getResponse();
504: $this->updateCallContext($connectionResponse, $callContext);
505: $httpStatusCode = $connectionResponse->getHttpStatusCode();
506: if ($httpStatusCode >= 400) {
507: $response = $this->getResponseFactory()->createResponse($connectionResponse, $responseClassMap);
508: throw new ErrorResponseException($httpStatusCode, $response);
509: }
510: }
511:
512: /**
513: * @param ConnectionResponse $response
514: * @param CallContext|null $callContext
515: *
516: * @return void
517: */
518: protected function updateCallContext(ConnectionResponse $response, ?CallContext $callContext = null): void
519: {
520: if ($callContext) {
521: $callContext->setIdempotenceRequestTimestamp(
522: $response->getHeaderValue('X-GCS-Idempotence-Request-Timestamp')
523: );
524: }
525: }
526:
527: /**
528: * @param string $relativeUriPath
529: * @param RequestObject|null $requestParameters
530: *
531: * @return string
532: * @throws Exception
533: */
534: protected function getRequestUri(string $relativeUriPath, ?RequestObject $requestParameters = null): string
535: {
536: return
537: $this->apiEndpoint .
538: $this->getRelativeUriPathWithRequestParameters($relativeUriPath, $requestParameters);
539: }
540:
541: /**
542: * @param string $httpMethod
543: * @param string $relativeUriPathWithRequestParameters
544: * @param string|null $contentType
545: * @param string $clientMetaInfo
546: * @param CallContext|null $callContext
547: *
548: * @return string[]
549: */
550: protected function getRequestHeaders(
551: string $httpMethod,
552: string $relativeUriPathWithRequestParameters,
553: ?string $contentType,
554: string $clientMetaInfo = '',
555: ?CallContext $callContext = null
556: ): array {
557: $rfc2616Date = self::getRfc161Date();
558: $requestHeaders = array();
559: if ($contentType) {
560: $requestHeaders['Content-Type'] = $contentType;
561: }
562: $requestHeaders['Date'] = $rfc2616Date;
563: if ($clientMetaInfo) {
564: $requestHeaders['X-GCS-ClientMetaInfo'] = $clientMetaInfo;
565: }
566: $requestHeaders['X-GCS-ServerMetaInfo'] = $this->metadataProvider->getServerMetaInfoValue();
567: if ($callContext && strlen($callContext->getIdempotenceKey()) > 0) {
568: $requestHeaders['X-GCS-Idempotence-Key'] = $callContext->getIdempotenceKey();
569: }
570: $requestHeaders['Authorization'] = $this->authenticator->getAuthorization(
571: $httpMethod,
572: $relativeUriPathWithRequestParameters,
573: $requestHeaders
574: );
575: return $requestHeaders;
576: }
577:
578: /**
579: * @return string
580: */
581: protected static function getRfc161Date(): string
582: {
583: return gmdate('D, d M Y H:i:s T');
584: }
585:
586: /**
587: * @param string $relativeUriPath
588: * @param RequestObject|null $requestParameters
589: *
590: * @return string
591: */
592: protected function getRelativeUriPathWithRequestParameters(
593: string $relativeUriPath,
594: ?RequestObject $requestParameters = null
595: ): string {
596: if (is_null($requestParameters)) {
597: return $relativeUriPath;
598: }
599: $requestParameterObjectVars = get_object_vars($requestParameters);
600: if (count($requestParameterObjectVars) == 0) {
601: return $relativeUriPath;
602: }
603: $httpQuery = http_build_query($requestParameterObjectVars);
604: if ($httpQuery === '') {
605: return $relativeUriPath;
606: }
607: // remove [0], [1] etc. that are added if properties are arrays
608: $httpQuery = preg_replace('/%5B\d+%5D/imU', '', $httpQuery);
609: return $relativeUriPath . '?' . $httpQuery;
610: }
611:
612: /**
613: * @return ResponseFactory
614: */
615: protected function getResponseFactory(): ResponseFactory
616: {
617: if (is_null($this->responseFactory)) {
618: $this->responseFactory = new ResponseFactory();
619: }
620: return $this->responseFactory;
621: }
622: }
623: