77namespace Magento \Dhl \Model ;
88
99use Magento \Catalog \Model \Product \Type ;
10+ use Magento \Framework \App \ObjectManager ;
1011use Magento \Framework \App \ProductMetadataInterface ;
12+ use Magento \Framework \Async \CallbackDeferred ;
13+ use Magento \Framework \Async \ProxyDeferredFactory ;
14+ use Magento \Framework \HTTP \AsyncClient \HttpResponseDeferredInterface ;
15+ use Magento \Framework \HTTP \AsyncClient \Request ;
16+ use Magento \Framework \HTTP \AsyncClientInterface ;
1117use Magento \Framework \Module \Dir ;
1218use Magento \Sales \Exception \DocumentValidationException ;
1319use Magento \Sales \Model \Order \Shipment ;
@@ -197,6 +203,8 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
197203
198204 /**
199205 * @var \Magento\Framework\HTTP\ZendClientFactory
206+ * @deprecated Use asynchronous client.
207+ * @see $httpClient
200208 */
201209 protected $ _httpClientFactory ;
202210
@@ -219,6 +227,16 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
219227 */
220228 private $ productMetadata ;
221229
230+ /**
231+ * @var AsyncClientInterface
232+ */
233+ private $ httpClient ;
234+
235+ /**
236+ * @var ProxyDeferredFactory
237+ */
238+ private $ proxyDeferredFactory ;
239+
222240 /**
223241 * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
224242 * @param \Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory $rateErrorFactory
@@ -247,6 +265,8 @@ class Carrier extends \Magento\Dhl\Model\AbstractDhl implements \Magento\Shippin
247265 * @param array $data
248266 * @param \Magento\Dhl\Model\Validator\XmlValidator|null $xmlValidator
249267 * @param ProductMetadataInterface|null $productMetadata
268+ * @param AsyncClientInterface|null $httpClient
269+ * @param ProxyDeferredFactory|null $proxyDeferredFactory
250270 * @SuppressWarnings(PHPMD.ExcessiveParameterList)
251271 */
252272 public function __construct (
@@ -276,7 +296,9 @@ public function __construct(
276296 \Magento \Framework \HTTP \ZendClientFactory $ httpClientFactory ,
277297 array $ data = [],
278298 \Magento \Dhl \Model \Validator \XmlValidator $ xmlValidator = null ,
279- ProductMetadataInterface $ productMetadata = null
299+ ProductMetadataInterface $ productMetadata = null ,
300+ ?AsyncClientInterface $ httpClient = null ,
301+ ?ProxyDeferredFactory $ proxyDeferredFactory = null
280302 ) {
281303 $ this ->readFactory = $ readFactory ;
282304 $ this ->_carrierHelper = $ carrierHelper ;
@@ -308,10 +330,11 @@ public function __construct(
308330 if ($ this ->getConfigData ('content_type ' ) == self ::DHL_CONTENT_TYPE_DOC ) {
309331 $ this ->_freeMethod = 'free_method_doc ' ;
310332 }
311- $ this ->xmlValidator = $ xmlValidator
312- ?: \Magento \Framework \App \ObjectManager::getInstance ()->get (XmlValidator::class);
313- $ this ->productMetadata = $ productMetadata
314- ?: \Magento \Framework \App \ObjectManager::getInstance ()->get (ProductMetadataInterface::class);
333+ $ this ->xmlValidator = $ xmlValidator ?? ObjectManager::getInstance ()->get (XmlValidator::class);
334+ $ this ->productMetadata = $ productMetadata ?? ObjectManager::getInstance ()->get (ProductMetadataInterface::class);
335+ $ this ->httpClient = $ httpClient ?? ObjectManager::getInstance ()->get (AsyncClientInterface::class);
336+ $ this ->proxyDeferredFactory = $ proxyDeferredFactory
337+ ?? ObjectManager::getInstance ()->get (ProxyDeferredFactory::class);
315338 }
316339
317340 /**
@@ -348,7 +371,6 @@ public function collectRates(RateRequest $request)
348371
349372 $ requestDhl = clone $ request ;
350373 $ this ->setStore ($ requestDhl ->getStoreId ());
351-
352374 $ origCompanyName = $ this ->_getDefaultValue (
353375 $ requestDhl ->getOrigCompanyName (),
354376 \Magento \Store \Model \Information::XML_PATH_STORE_INFO_NAME
@@ -357,18 +379,27 @@ public function collectRates(RateRequest $request)
357379 $ origState = $ this ->_getDefaultValue ($ requestDhl ->getOrigState (), Shipment::XML_PATH_STORE_REGION_ID );
358380 $ origCity = $ this ->_getDefaultValue ($ requestDhl ->getOrigCity (), Shipment::XML_PATH_STORE_CITY );
359381 $ origPostcode = $ this ->_getDefaultValue ($ requestDhl ->getOrigPostcode (), Shipment::XML_PATH_STORE_ZIP );
360-
361382 $ requestDhl ->setOrigCompanyName ($ origCompanyName )
362383 ->setCountryId ($ origCountryId )
363384 ->setOrigState ($ origState )
364385 ->setOrigCity ($ origCity )
365386 ->setOrigPostal ($ origPostcode );
366387 $ this ->setRequest ($ requestDhl );
367-
368- $ this ->_result = $ this ->_getQuotes ();
369- $ this ->_updateFreeMethodQuote ($ request );
370-
371- return $ this ->_result ;
388+ //Loading quotes
389+ //Saving $result to use proper result with the callback
390+ $ this ->_result = $ result = $ this ->_getQuotes ();
391+ //After quotes are loaded parsing the response.
392+ return $ this ->proxyDeferredFactory ->createFor (
393+ Result::class,
394+ new CallbackDeferred (
395+ function () use ($ request , $ result ) {
396+ $ this ->_result = $ result ;
397+ $ this ->_updateFreeMethodQuote ($ request );
398+
399+ return $ this ->_result ;
400+ }
401+ )
402+ );
372403 }
373404
374405 /**
@@ -715,6 +746,7 @@ protected function _getWeight($weight, $maxWeight = false, $configWeightUnit = f
715746 * @return array
716747 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
717748 * @SuppressWarnings(PHPMD.NPathComplexity)
749+ * phpcs:disable Generic.Metrics.NestingLevel
718750 */
719751 protected function _getAllItems ()
720752 {
@@ -799,6 +831,7 @@ protected function _getAllItems()
799831
800832 return $ fullItems ;
801833 }
834+ //phpcs:enable
802835
803836 /**
804837 * Make pieces
@@ -931,56 +964,126 @@ protected function _addDimension($nodePiece)
931964 }
932965
933966 /**
934- * Get shipping quotes
967+ * Process response received from DHL's API for quotes.
935968 *
936- * @return \Magento\Framework\Model\AbstractModel|Result
969+ * @param array $responsesData
970+ * @return Error|Result
937971 */
938- protected function _getQuotes ( )
972+ private function processQuotesResponses ( array $ responsesData )
939973 {
940- $ responseBody = '' ;
941- try {
942- for ($ offset = 0 ; $ offset <= self ::UNAVAILABLE_DATE_LOOK_FORWARD ; $ offset ++) {
943- $ debugPoint = [];
944-
945- $ requestXml = $ this ->_buildQuotesRequestXml ();
946- $ date = date (self ::REQUEST_DATE_FORMAT , strtotime ($ this ->_getShipDate () . " + {$ offset } days " ));
947- $ this ->_setQuotesRequestXmlDate ($ requestXml , $ date );
948-
949- $ request = $ requestXml ->asXML ();
950- $ debugPoint ['request ' ] = $ this ->filterDebugData ($ request );
951- $ responseBody = $ this ->_getCachedQuotes ($ request );
952- $ debugPoint ['from_cache ' ] = $ responseBody === null ;
953-
954- if ($ debugPoint ['from_cache ' ]) {
955- $ responseBody = $ this ->_getQuotesFromServer ($ request );
956- }
957-
958- $ debugPoint ['response ' ] = $ this ->filterDebugData ($ responseBody );
959-
960- $ bodyXml = $ this ->_xmlElFactory ->create (['data ' => $ responseBody ]);
974+ usort (
975+ $ responsesData ,
976+ function (array $ a , array $ b ): int {
977+ return $ a ['date ' ] <=> $ b ['date ' ];
978+ }
979+ );
980+ /** @var string $lastResponse */
981+ $ lastResponse = '' ;
982+ //Processing different dates
983+ foreach ($ responsesData as $ responseData ) {
984+ $ debugPoint = [];
985+ $ debugPoint ['request ' ] = $ this ->filterDebugData ($ responseData ['request ' ]);
986+ $ debugPoint ['response ' ] = $ this ->filterDebugData ($ responseData ['body ' ]);
987+ $ debugPoint ['from_cache ' ] = $ responseData ['from_cache ' ];
988+ $ unavailable = false ;
989+ try {
990+ //Getting availability
991+ $ bodyXml = $ this ->_xmlElFactory ->create (['data ' => $ responseData ['body ' ]]);
961992 $ code = $ bodyXml ->xpath ('//GetQuoteResponse/Note/Condition/ConditionCode ' );
962993 if (isset ($ code [0 ]) && (int )$ code [0 ] == self ::CONDITION_CODE_SERVICE_DATE_UNAVAILABLE ) {
963- $ debugPoint ['info ' ] = sprintf (__ ("DHL service is not available at %s date " ), $ date );
964- } else {
965- $ this ->_debug ($ debugPoint );
966- break ;
994+ $ debugPoint ['info ' ] = sprintf (
995+ __ ("DHL service is not available at %s date " ),
996+ $ responseData ['date ' ]
997+ );
998+ $ unavailable = true ;
967999 }
968-
969- $ this ->_setCachedQuotes ($ request , $ responseBody );
1000+ } catch (\Throwable $ exception ) {
1001+ //Failed to read response
1002+ $ unavailable = true ;
1003+ $ this ->_errors [$ exception ->getCode ()] = $ exception ->getMessage ();
1004+ }
1005+ if ($ unavailable ) {
1006+ //Cannot get rates.
9701007 $ this ->_debug ($ debugPoint );
1008+ break ;
9711009 }
972- } catch (\Exception $ e ) {
973- $ this ->_errors [$ e ->getCode ()] = $ e ->getMessage ();
1010+ //Caching rates
1011+ $ this ->_setCachedQuotes ($ responseData ['request ' ], $ responseData ['body ' ]);
1012+ $ this ->_debug ($ debugPoint );
1013+ //Will only process rates available for the latest date possible.
1014+ $ lastResponse = $ responseData ['body ' ];
9741015 }
9751016
976- return $ this ->_parseResponse ($ responseBody );
1017+ return $ this ->_parseResponse ($ lastResponse );
1018+ }
1019+
1020+ /**
1021+ * Get shipping quotes
1022+ *
1023+ * @return \Magento\Framework\Model\AbstractModel|Result
1024+ */
1025+ protected function _getQuotes ()
1026+ {
1027+ $ responseBodies = [];
1028+ /** @var HttpResponseDeferredInterface[][] $deferredResponses */
1029+ $ deferredResponses = [];
1030+ $ requestXml = $ this ->_buildQuotesRequestXml ();
1031+ for ($ offset = 0 ; $ offset <= self ::UNAVAILABLE_DATE_LOOK_FORWARD ; $ offset ++) {
1032+ $ date = date (self ::REQUEST_DATE_FORMAT , strtotime ($ this ->_getShipDate () . " + {$ offset } days " ));
1033+ $ this ->_setQuotesRequestXmlDate ($ requestXml , $ date );
1034+ $ request = $ requestXml ->asXML ();
1035+ $ responseBody = $ this ->_getCachedQuotes ($ request );
1036+
1037+ if ($ responseBody === null ) {
1038+ $ deferredResponses [] = [
1039+ 'deferred ' => $ this ->httpClient ->request (
1040+ new Request (
1041+ (string )$ this ->getConfigData ('gateway_url ' ),
1042+ Request::METHOD_POST ,
1043+ ['Content-Type ' => 'application/xml ' ],
1044+ utf8_encode ($ request )
1045+ )
1046+ ),
1047+ 'date ' => $ date ,
1048+ 'request ' => $ request
1049+ ];
1050+ } else {
1051+ $ responseBodies [] = [
1052+ 'body ' => $ responseBody ,
1053+ 'date ' => $ date ,
1054+ 'request ' => $ request ,
1055+ 'from_cache ' => true
1056+ ];
1057+ }
1058+ }
1059+
1060+ return $ this ->proxyDeferredFactory ->createFor (
1061+ Result::class,
1062+ new CallbackDeferred (
1063+ function () use ($ deferredResponses , $ responseBodies ) {
1064+ //Loading rates not found in cache
1065+ foreach ($ deferredResponses as $ deferredResponseData ) {
1066+ $ responseBodies [] = [
1067+ 'body ' => $ deferredResponseData ['deferred ' ]->get ()->getBody (),
1068+ 'date ' => $ deferredResponseData ['date ' ],
1069+ 'request ' => $ deferredResponseData ['request ' ],
1070+ 'from_cache ' => false
1071+ ];
1072+ }
1073+
1074+ return $ this ->processQuotesResponses ($ responseBodies );
1075+ }
1076+ )
1077+ );
9771078 }
9781079
9791080 /**
9801081 * Get shipping quotes from DHL service
9811082 *
9821083 * @param string $request
9831084 * @return string
1085+ * @deprecated Use asynchronous client.
1086+ * @see _getQuotes()
9841087 */
9851088 protected function _getQuotesFromServer ($ request )
9861089 {
@@ -1568,21 +1671,23 @@ protected function _doRequest()
15681671 $ xml ->addChild ('LabelImageFormat ' , 'PDF ' , '' );
15691672
15701673 $ request = $ xml ->asXML ();
1571- if (! $ request && !(mb_detect_encoding ($ request ) == 'UTF-8 ' )) {
1674+ if ($ request && !(mb_detect_encoding ($ request ) == 'UTF-8 ' )) {
15721675 $ request = utf8_encode ($ request );
15731676 }
15741677
15751678 $ responseBody = $ this ->_getCachedQuotes ($ request );
15761679 if ($ responseBody === null ) {
15771680 $ debugData = ['request ' => $ this ->filterDebugData ($ request )];
15781681 try {
1579- /** @var \Magento\Framework\HTTP\ZendClient $client */
1580- $ client = $ this ->_httpClientFactory ->create ();
1581- $ client ->setUri ((string )$ this ->getConfigData ('gateway_url ' ));
1582- $ client ->setConfig (['maxredirects ' => 0 , 'timeout ' => 30 ]);
1583- $ client ->setRawData ($ request );
1584- $ responseBody = $ client ->request (\Magento \Framework \HTTP \ZendClient::POST )->getBody ();
1585- $ responseBody = utf8_decode ($ responseBody );
1682+ $ response = $ this ->httpClient ->request (
1683+ new Request (
1684+ (string )$ this ->getConfigData ('gateway_url ' ),
1685+ Request::METHOD_POST ,
1686+ ['Content-Type ' => 'application/xml ' ],
1687+ $ request
1688+ )
1689+ );
1690+ $ responseBody = utf8_decode ($ response ->get ()->getBody ());
15861691 $ debugData ['result ' ] = $ this ->filterDebugData ($ responseBody );
15871692 $ this ->_setCachedQuotes ($ request , $ responseBody );
15881693 } catch (\Exception $ e ) {
@@ -1743,12 +1848,15 @@ protected function _getXMLTracking($trackings)
17431848 if ($ responseBody === null ) {
17441849 $ debugData = ['request ' => $ this ->filterDebugData ($ request )];
17451850 try {
1746- /** @var \Magento\Framework\HTTP\ZendClient $client */
1747- $ client = $ this ->_httpClientFactory ->create ();
1748- $ client ->setUri ((string )$ this ->getConfigData ('gateway_url ' ));
1749- $ client ->setConfig (['maxredirects ' => 0 , 'timeout ' => 30 ]);
1750- $ client ->setRawData ($ request );
1751- $ responseBody = $ client ->request (\Magento \Framework \HTTP \ZendClient::POST )->getBody ();
1851+ $ response = $ this ->httpClient ->request (
1852+ new Request (
1853+ (string )$ this ->getConfigData ('gateway_url ' ),
1854+ Request::METHOD_POST ,
1855+ ['Content-Type ' => 'application/xml ' ],
1856+ $ request
1857+ )
1858+ );
1859+ $ responseBody = $ response ->get ()->getBody ();
17521860 $ debugData ['result ' ] = $ this ->filterDebugData ($ responseBody );
17531861 $ this ->_setCachedQuotes ($ request , $ responseBody );
17541862 } catch (\Exception $ e ) {
@@ -1850,6 +1958,7 @@ protected function _parseXmlTrackingResponse($trackings, $response)
18501958 $ result ->append ($ error );
18511959 }
18521960 }
1961+ $ this ->_errors = [];
18531962
18541963 $ this ->_result = $ result ;
18551964 }
@@ -1944,6 +2053,7 @@ protected function _prepareShippingLabelContent(\SimpleXMLElement $xml)
19442053 }
19452054 $ result ->setTrackingNumber ((string )$ xml ->AirwayBillNumber );
19462055 $ labelContent = (string )$ xml ->LabelImage ->OutputImage ;
2056+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
19472057 $ result ->setShippingLabelContent (base64_decode ($ labelContent ));
19482058 } catch (\Exception $ e ) {
19492059 throw new \Magento \Framework \Exception \LocalizedException (__ ($ e ->getMessage ()));
0 commit comments