diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..36ea091 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# Auto detect text files and perform LF normalization +* text=auto +* text eol=lf + +# Convert images to binary +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.tiff binary +*.ico binary \ No newline at end of file diff --git a/composer.json b/composer.json index 9e91e0b..fece440 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "paynl/php-sdk", "description": "Software Development Kit for implementing Pay.'s API version 3", - "version": "0.2.0", + "version": "0.2.1", "type": "library", "require": { "php": "^8.1", diff --git a/config/config.global.php b/config/config.global.php index cd9a18c..e6ff123 100644 --- a/config/config.global.php +++ b/config/config.global.php @@ -7,5 +7,6 @@ 'username' => '', # Use AT-Code or SL-Code. Use AT-code together with API-Token. 'password' => '', # Use API token or secret. Use Secret in combination with SL-Code. ], - 'debug' => false -]; \ No newline at end of file + 'debug' => false, + 'useFileCaching' => true +]; diff --git a/samples/OrderCreate.php b/samples/OrderCreate.php index d70ddf2..56cb440 100644 --- a/samples/OrderCreate.php +++ b/samples/OrderCreate.php @@ -106,7 +106,6 @@ try { $request->setReference('SDK0123456789'); $payOrder = $request->start(); - echo get_class($payOrder); } catch (PayException $e) { echo '
';
     echo 'Technical message: ' . $e->getMessage() . PHP_EOL;
diff --git a/samples/ServiceGetConfig.php b/samples/ServiceGetConfig.php
index b24da48..cc17263 100644
--- a/samples/ServiceGetConfig.php
+++ b/samples/ServiceGetConfig.php
@@ -13,10 +13,9 @@
 $config->setUsername($_REQUEST['username'] ?? '');
 $config->setPassword($_REQUEST['password'] ?? '');
 
-
 try {
     $slCode = $_REQUEST['slcode'] ?? '';
-    $config = (new ServiceGetConfigRequest($slCode))->setConfig($config)->start();
+    $serviceConfig = (new ServiceGetConfigRequest($slCode))->setConfig($config)->start();
 } catch (PayException $e) {
     echo '
';
     echo 'Technical message: ' . $e->getMessage() . PHP_EOL;
@@ -28,18 +27,18 @@
 
 echo '
';
 
-echo $config->getCode() . ' - ' . $config->getName() . PHP_EOL;
+echo $serviceConfig->getCode() . ' - ' . $serviceConfig->getName() . PHP_EOL;
 
-$banks = $config->getBanks();
+$banks = $serviceConfig->getBanks();
 print_r($banks);
 
-$terminals = $config->getTerminals();
+$terminals = $serviceConfig->getTerminals();
 print_r($terminals);
 
-$tguList = $config->getCores();
+$tguList = $serviceConfig->getCores();
 print_r($tguList);
 
-$paymentMethods = $config->getPaymentMethods();
+$paymentMethods = $serviceConfig->getPaymentMethods();
 foreach ($paymentMethods as $method) {
     echo $method->getId() . ' - ';
     echo $method->getName() . ' - ';
@@ -51,6 +50,6 @@
     echo PHP_EOL;
 }
 
-foreach ($config->getCheckoutOptions() as $checkoutOption) {
+foreach ($serviceConfig->getCheckoutOptions() as $checkoutOption) {
     echo '=> TAG: ' . $checkoutOption->getTag() . PHP_EOL;
 }
diff --git a/src/Config/Config.php b/src/Config/Config.php
index d9573e0..a987305 100644
--- a/src/Config/Config.php
+++ b/src/Config/Config.php
@@ -371,6 +371,14 @@ public function isEmpty()
         return false;
     }
 
+    /**
+     * @return boolean
+     */
+    public function isCacheEnabled()
+    {
+        return ($this->data['useFileCaching'] ?? 0) == 1;
+    }
+
     /**
      * @return string
      */
@@ -389,6 +397,16 @@ public function setPassword(string $password): self
         return $this;
     }
 
+    /**
+     * @param boolean $caching
+     * @return self
+     */
+    public function setCaching(bool $caching): self
+    {
+        $this->data['useFileCaching'] = $caching;
+        return $this;
+    }
+
     /**
      * @return string
      */
diff --git a/src/Helpers/StaticCacheTrait.php b/src/Helpers/StaticCacheTrait.php
new file mode 100644
index 0000000..19113f0
--- /dev/null
+++ b/src/Helpers/StaticCacheTrait.php
@@ -0,0 +1,63 @@
+ $this->orderId
+            'transactionId' => $this->orderId
         ];
     }
 
@@ -53,9 +57,25 @@ public function getBodyParameters(): array
      */
     public function start(): PayOrder
     {
-        # Always use TGU-1 for orderStatus
-        $this->config->setCore(Config::TGU1);
-        
-        return parent::start();
+        $cacheKey = 'order_status_' . md5(json_encode([$this->config->getUsername(), $this->orderId]));
+
+        if ($this->hasStaticCache($cacheKey)) {
+            return $this->getStaticCacheValue($cacheKey);
+        }
+
+        if ($this->config->isCacheEnabled()) {
+            $cache = new PayCache();
+            return $cache->get($cacheKey, function () use ($cacheKey) {
+                return $this->staticCache($cacheKey, function () {
+                    $this->config->setCore(Config::TGU1);
+                    return parent::start();
+                });
+            }, 3); # 3 seconds file caching
+        }
+
+        return $this->staticCache($cacheKey, function () {
+            $this->config->setCore(Config::TGU1);
+            return parent::start();
+        });
     }
-}
\ No newline at end of file
+}
diff --git a/src/Model/Request/ServiceGetConfigRequest.php b/src/Model/Request/ServiceGetConfigRequest.php
index 767368e..cee0222 100644
--- a/src/Model/Request/ServiceGetConfigRequest.php
+++ b/src/Model/Request/ServiceGetConfigRequest.php
@@ -8,6 +8,8 @@
 use PayNL\Sdk\Request\RequestData;
 use PayNL\Sdk\Model\Response\ServiceGetConfigResponse;
 use PayNL\Sdk\Request\RequestInterface;
+use PayNL\Sdk\Util\PayCache;
+use PayNL\Sdk\Helpers\StaticCacheTrait;
 
 /**
  * Class ServiceGetConfigRequest
@@ -18,12 +20,17 @@
  */
 class ServiceGetConfigRequest extends RequestData
 {
+    use StaticCacheTrait;
+
+    /**
+     * @var string|mixed
+     */
     private string $serviceId;
 
     /**
-     * @param $serviceId
+     * @param string $serviceId
      */
-    public function __construct($serviceId = '')
+    public function __construct(string $serviceId = '')
     {
         $this->serviceId = $serviceId;
         parent::__construct('GetConfig', '/services/config', RequestInterface::METHOD_GET);
@@ -53,9 +60,35 @@ public function getBodyParameters(): array
      * @throws PayException
      */
     public function start(): ServiceGetConfigResponse
+    {
+        $cacheKey = 'service_getconfig_' . md5(json_encode([$this->config->getUsername(), $this->config->getPassword(), $this->serviceId]));
+
+        if ($this->hasStaticCache($cacheKey)) {
+            return $this->getStaticCacheValue($cacheKey);
+        }
+
+        if ($this->config->isCacheEnabled()) {
+            $cache = new PayCache();
+            return $cache->get($cacheKey, function () use ($cacheKey) {
+                return $this->staticCache($cacheKey, function () {
+                    return $this->startAPI();
+                });
+            }, 5);
+        }
+
+        return $this->staticCache($cacheKey, function () {
+            return $this->startAPI();
+        });
+    }
+
+    /**
+     * @return ServiceGetConfigResponse
+     * @throws PayException
+     */
+    private function startAPI(): ServiceGetConfigResponse
     {
         $this->config->setCore('https://rest.pay.nl');
         $this->config->setVersion(2);
         return parent::start();
     }
-}
\ No newline at end of file
+}
diff --git a/src/Model/Request/TransactionStatusRequest.php b/src/Model/Request/TransactionStatusRequest.php
index b328084..bf6629f 100644
--- a/src/Model/Request/TransactionStatusRequest.php
+++ b/src/Model/Request/TransactionStatusRequest.php
@@ -4,10 +4,13 @@
 
 namespace PayNL\Sdk\Model\Request;
 
+use PayNL\Sdk\Config\Config;
 use PayNL\Sdk\Exception\PayException;
 use PayNL\Sdk\Request\RequestData;
 use PayNL\Sdk\Model\Pay\PayOrder;
 use PayNL\Sdk\Request\RequestInterface;
+use PayNL\Sdk\Helpers\StaticCacheTrait;
+use PayNL\Sdk\Util\PayCache;
 
 /**
  * Class TransactionStatusRequest
@@ -17,12 +20,14 @@
  */
 class TransactionStatusRequest extends RequestData
 {
+    use StaticCacheTrait;
+
     private string $orderId;
 
     /**
-     * @param $orderid
+     * @param string $orderId
      */
-    public function __construct($orderId)
+    public function __construct(string $orderId)
     {
         $this->orderId = $orderId;
         parent::__construct('TransactionStatus', '/transactions/%transactionId%/status', RequestInterface::METHOD_GET);
@@ -48,12 +53,29 @@ public function getBodyParameters(): array
 
     /**
      * @return PayOrder
-     * @throws PayException
+     * @throws \Exception
      */
     public function start(): PayOrder
     {
-        # Always use rest.pay.nl for this status request
-        $this->config->setCore('https://rest.pay.nl');
-        return parent::start();
+        $cacheKey = 'transaction_status_' . md5(json_encode([$this->config->getUsername(), $this->orderId]));
+
+        if ($this->hasStaticCache($cacheKey)) {
+            return $this->getStaticCacheValue($cacheKey);
+        }
+
+        if ($this->config->isCacheEnabled()) {
+            $cache = new PayCache();
+            return $cache->get($cacheKey, function () use ($cacheKey) {
+                return $this->staticCache($cacheKey, function () {
+                    $this->config->setCore('https://rest.pay.nl');
+                    return parent::start();
+                });
+            }, 3); # 3 seconds file caching
+        }
+
+        return $this->staticCache($cacheKey, function () {
+            $this->config->setCore('https://rest.pay.nl');
+            return parent::start();
+        });
     }
-}
\ No newline at end of file
+}
diff --git a/src/Model/Response/ServiceGetConfigResponse.php b/src/Model/Response/ServiceGetConfigResponse.php
index 4d8d2c4..be9712a 100644
--- a/src/Model/Response/ServiceGetConfigResponse.php
+++ b/src/Model/Response/ServiceGetConfigResponse.php
@@ -335,11 +335,30 @@ public function setTguList(array $tguList): void
     }
 
     /**
+     * Provides a core-list prepared with web protocol.
      * @return array
      */
     public function getCores(): array
     {
-        return $this->getTguList();
+        $cores = $this->getTguList();
+
+        $payDomain = false;
+        foreach ($cores as &$core) {
+            $domain = $core['domain'];
+
+            if (in_array($domain, ['pay.nl', 'connect.pay.nl'])) {
+                $payDomain = true;
+            }
+
+            $core['domain'] = 'https://' . $domain;
+            $core['label'] = $domain;
+        }
+
+        if ($payDomain !== true) {
+            array_unshift($cores, ['domain' => 'https://connect.pay.nl', 'label' => 'connect.pay.nl']);
+        }
+
+        return $cores;
     }
 
     /**
diff --git a/src/Request/RequestData.php b/src/Request/RequestData.php
index f357fad..fa702d1 100644
--- a/src/Request/RequestData.php
+++ b/src/Request/RequestData.php
@@ -43,7 +43,8 @@ public function __construct(string $mapperName, string $uri, string $requestMeth
      */
     public function setConfig(Config $config): self
     {
-        $this->config = $config;
+        $this->config = (new Config(require __DIR__ . '/../../config/config.global.php'));
+        $this->config->merge($config);
         return $this;
     }
 
@@ -56,16 +57,17 @@ public function setApplication(Application $application): void
         $this->application = $application;
     }
 
+
     /**
-     * @return mixed
+     * @return Config|null
      * @throws PayException
-     * @throws Exception
      */
-    public function start()
+    private function getConfig(): Config
     {
-        $config = (new Config(require __DIR__ . '/../../config/config.global.php'));
-        if (!empty($this->config)) {
-            $config->merge($this->config);
+        if (empty($this->config)) {
+            $config = (new Config(require __DIR__ . '/../../config/config.global.php'));
+        } else {
+            $config = $this->config;
         }
 
         if (!empty($config->getFailoverUrl())) {
@@ -76,6 +78,17 @@ public function start()
             throw new PayException('Please check your config', 0, 0);
         }
 
+        return $config;
+    }
+
+    /**
+     * @return mixed
+     * @throws PayException
+     */
+    public function start()
+    {
+        $config = $this->getConfig();
+
         try {
             if (empty($this->application)) {
                 $this->application = Application::init($config);
diff --git a/src/Util/Exchange.php b/src/Util/Exchange.php
index 06e54a1..7924edb 100644
--- a/src/Util/Exchange.php
+++ b/src/Util/Exchange.php
@@ -76,7 +76,7 @@ public function eventCapture()
      *
      * @param boolean $result
      * @param string $message
-     * @param boolean $returnOutput If true, then this method returs the output string
+     * @param boolean $returnOutput
      * @return false|string|void
      */
     public function setResponse(bool $result, string $message, bool $returnOutput = false)
diff --git a/src/Util/PayCache.php b/src/Util/PayCache.php
new file mode 100644
index 0000000..d557db8
--- /dev/null
+++ b/src/Util/PayCache.php
@@ -0,0 +1,137 @@
+cacheDir = $cacheDir ?? sys_get_temp_dir() . '/cache_pay_phpsdk';
+        $this->defaultTtl = $defaultTtl;
+
+        if (!is_dir($this->cacheDir)) {
+            if (!@mkdir($this->cacheDir, 0777, true) && !is_dir($this->cacheDir)) {
+                $this->enabled = false;
+                return;
+            }
+        }
+
+        if (!is_writable($this->cacheDir)) {
+            $this->enabled = false;
+        }
+    }
+
+    /**
+     * @param string $key
+     * @param callable|null $callback
+     * @param integer|null $ttl
+     * @return mixed|null
+     */
+    public function get(string $key, callable $callback = null, int $ttl = null): mixed
+    {
+        if (!$this->enabled) {
+            return $callback ? $callback() : null;
+        }
+
+        $file = $this->getCacheFile($key);
+
+        if (file_exists($file)) {
+            $data = @unserialize(file_get_contents($file));
+
+            if ($data !== false && isset($data['expires'], $data['value'])) {
+                if ($data['expires'] >= time()) {
+                    return $data['value'];
+                }
+            }
+
+            # Cache expired or invalid
+            @unlink($file);
+        }
+
+        if ($callback !== null) {
+            $value = $callback();
+            $this->set($key, $value, $ttl);
+            return $value;
+        }
+
+        return null;
+    }
+
+    /**
+     * @param string $key
+     * @param mixed $value
+     * @param integer|null $ttl
+     * @return void
+     */
+    public function set(string $key, mixed $value, int $ttl = null): void
+    {
+        if (!$this->enabled) {
+            return;
+        }
+
+        $ttl = $ttl ?? $this->defaultTtl;
+        $file = $this->getCacheFile($key);
+
+        $data = [
+            'expires' => time() + $ttl,
+            'value' => $value
+        ];
+
+        @file_put_contents($file, serialize($data), LOCK_EX);
+    }
+
+    /**
+     * @param string $key
+     * @return void
+     */
+    public function delete(string $key): void
+    {
+        if (!$this->enabled) {
+            return;
+        }
+
+        $file = $this->getCacheFile($key);
+        if (file_exists($file)) {
+            @unlink($file);
+        }
+    }
+
+    /**
+     * @return void
+     */
+    public function clear(): void
+    {
+        if (!$this->enabled) {
+            return;
+        }
+
+        foreach (glob($this->cacheDir . '/*') ?: [] as $file) {
+            @unlink($file);
+        }
+    }
+
+    /**
+     * @param string $key
+     * @return string
+     */
+    private function getCacheFile(string $key): string
+    {
+        return $this->cacheDir . '/' . md5($key) . '.cache';
+    }
+
+    /**
+     * @return boolean
+     */
+    public function isEnabled(): bool
+    {
+        return $this->enabled;
+    }
+}
diff --git a/src/Util/Text.php b/src/Util/Text.php
index acba9a6..ad15163 100644
--- a/src/Util/Text.php
+++ b/src/Util/Text.php
@@ -20,6 +20,7 @@ class Text
     public static function getFriendlyMessage(string $errorMessage)
     {
         $friendlyMessages = [
+          'requested payment method is not enabled' => 'This payment method is not available',
           'INVALID_TRANSACTION_STAT' => 'Transaction not ready for refund.',
           'username can not be empty' => 'Connection error. Please check your connection credentials.',
           'bestelling kon niet worden gevonden' => 'Your order could not be found',