@@ -44,6 +44,8 @@ class Nvp extends \Magento\Paypal\Model\Api\AbstractApi
4444
4545 public const DO_EXPRESS_CHECKOUT_PAYMENT = 'DoExpressCheckoutPayment ' ;
4646
47+ public const DO_EXPRESS_CHECKOUT = 'DoExpressCheckout ' ;
48+
4749 public const CALLBACK_RESPONSE = 'CallbackResponse ' ;
4850
4951 /**
@@ -687,7 +689,11 @@ class Nvp extends \Magento\Paypal\Model\Api\AbstractApi
687689 *
688690 * @var array
689691 */
690- protected $ _requiredResponseParams = [self ::DO_DIRECT_PAYMENT => ['ACK ' , 'CORRELATIONID ' , 'AMT ' ]];
692+ protected $ _requiredResponseParams = [
693+ self ::DO_DIRECT_PAYMENT => ['ACK ' , 'CORRELATIONID ' , 'AMT ' ],
694+ self ::DO_EXPRESS_CHECKOUT => ['ACK ' ],
695+ self ::DO_EXPRESS_CHECKOUT_PAYMENT => ['ACK ' ]
696+ ];
691697
692698 /**
693699 * Warning codes recollected after each API call
@@ -737,6 +743,11 @@ class Nvp extends \Magento\Paypal\Model\Api\AbstractApi
737743 */
738744 protected $ _headers = [];
739745
746+ /**
747+ * @var Curl
748+ */
749+ private $ curl ;
750+
740751 /**
741752 * @param \Magento\Customer\Helper\Address $customerAddress
742753 * @param \Psr\Log\LoggerInterface $logger
@@ -1154,15 +1165,13 @@ protected function _postProcessResponse($response)
11541165 }
11551166
11561167 /**
1157- * Do the API call
1168+ * Prepare request for the API call
11581169 *
11591170 * @param string $methodName
11601171 * @param array $request
11611172 * @return array
1162- * @throws ClientException|\Magento\Framework\Exception\LocalizedException|\Exception
1163- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
11641173 */
1165- public function call ( $ methodName , array $ request )
1174+ private function prepareRequest ( string $ methodName , array $ request ): array
11661175 {
11671176 $ request = $ this ->_addMethodToRequest ($ methodName , $ request );
11681177 $ eachCallRequest = $ this ->_prepareEachCallRequest ($ methodName );
@@ -1172,28 +1181,83 @@ public function call($methodName, array $request)
11721181 unset($ eachCallRequest [$ key ]);
11731182 }
11741183 }
1175- $ request = $ this ->_exportToRequest ($ eachCallRequest , $ request );
1176- $ debugData = [ ' url ' => $ this -> getApiEndpoint (), $ methodName => $ request ];
1184+ return $ this ->_exportToRequest ($ eachCallRequest , $ request );
1185+ }
11771186
1178- try {
1179- /** @var Curl $http */
1180- $ http = $ this ->_curlFactory ->create ();
1187+ /**
1188+ * Creates a Curl object and sets parameters for the call
1189+ *
1190+ * @param array $request
1191+ * @return Curl
1192+ */
1193+ private function getCurl (array $ request = null ): Curl
1194+ {
1195+ if (!$ this ->curl ) {
1196+ $ this ->curl = $ this ->_curlFactory ->create ();
11811197 $ config = ['timeout ' => 60 , 'verifypeer ' => $ this ->_config ->getValue ('verifyPeer ' )];
11821198 if ($ this ->getUseProxy ()) {
11831199 $ config ['proxy ' ] = $ this ->getProxyHost () . ': ' . $ this ->getProxyPort ();
11841200 }
11851201 if ($ this ->getUseCertAuthentication ()) {
11861202 $ config ['ssl_cert ' ] = $ this ->getApiCertificate ();
11871203 }
1188- $ http ->setOptions ($ config );
1189- $ http ->write (
1190- Request::METHOD_POST ,
1191- $ this ->getApiEndpoint (),
1192- '1.1 ' ,
1193- $ this ->_headers ,
1194- $ this ->_buildQuery ($ request )
1204+ $ this ->curl ->setOptions ($ config );
1205+ if ($ request ) {
1206+ $ this ->curl ->write (
1207+ Request::METHOD_POST ,
1208+ $ this ->getApiEndpoint (),
1209+ '1.1 ' ,
1210+ $ this ->_headers ,
1211+ $ this ->_buildQuery ($ request )
1212+ );
1213+ }
1214+ }
1215+ return $ this ->curl ;
1216+ }
1217+
1218+ /**
1219+ * Checks if transport errors occurred and throws exception if needed
1220+ *
1221+ * @return void
1222+ * @throws ClientException
1223+ */
1224+ private function handleConnectionErrors (): void
1225+ {
1226+ if ($ this ->getCurl ()->getErrno ()) {
1227+ $ this ->_logger ->critical (
1228+ new \Exception (
1229+ sprintf (
1230+ 'PayPal NVP CURL connection error #%s: %s ' ,
1231+ $ this ->getCurl ()->getErrno (),
1232+ $ this ->getCurl ()->getError ()
1233+ )
1234+ )
1235+ );
1236+ $ this ->getCurl ()->close ();
1237+
1238+ throw new ClientException (
1239+ __ ('Payment Gateway is unreachable at the moment. Please use another payment option. ' )
11951240 );
1196- $ response = $ http ->read ();
1241+ }
1242+ // cUrl resource must be closed after checking it for errors
1243+ $ this ->getCurl ()->close ();
1244+ }
1245+
1246+ /**
1247+ * Do the API call
1248+ *
1249+ * @param string $methodName
1250+ * @param array $request
1251+ * @return array
1252+ * @throws ClientException|\Magento\Framework\Exception\LocalizedException|\Exception
1253+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
1254+ */
1255+ public function call ($ methodName , array $ request )
1256+ {
1257+ $ request = $ this ->prepareRequest ($ methodName , $ request );
1258+ $ debugData = ['url ' => $ this ->getApiEndpoint (), $ methodName => $ request ];
1259+ try {
1260+ $ response = $ this ->getCurl ($ request )->read ();
11971261 } catch (\Exception $ e ) {
11981262 $ debugData ['http_error ' ] = ['error ' => $ e ->getMessage (), 'code ' => $ e ->getCode ()];
11991263 $ this ->_debug ($ debugData );
@@ -1203,29 +1267,11 @@ public function call($methodName, array $request)
12031267 $ response = preg_split ('/^\r?$/m ' , $ response , 2 );
12041268 $ response = trim ($ response [1 ] ?? '' );
12051269 $ response = $ this ->_deformatNVP ($ response );
1206-
12071270 $ debugData ['response ' ] = $ response ;
12081271 $ this ->_debug ($ debugData );
1209-
12101272 $ response = $ this ->_postProcessResponse ($ response );
12111273
1212- // handle transport error
1213- if ($ http ->getErrno ()) {
1214- $ this ->_logger ->critical (
1215- new \Exception (
1216- sprintf ('PayPal NVP CURL connection error #%s: %s ' , $ http ->getErrno (), $ http ->getError ())
1217- )
1218- );
1219- $ http ->close ();
1220-
1221- throw new ClientException (
1222- __ ('Payment Gateway is unreachable at the moment. Please use another payment option. ' )
1223- );
1224- }
1225-
1226- // cUrl resource must be closed after checking it for errors
1227- $ http ->close ();
1228-
1274+ $ this ->handleConnectionErrors ();
12291275 if (!$ this ->_validateResponse ($ methodName , $ response )) {
12301276 $ this ->_logger ->critical (new \Exception (__ ('PayPal response hasn \'t required fields. ' )));
12311277 throw new \Magento \Framework \Exception \LocalizedException (
0 commit comments