View file core/libs/PayStack-PHP/vendor/yabacon/paystack-php/src/Paystack/Helpers/Router.php

File size: 7.68Kb
<?php

namespace Yabacon\Paystack\Helpers;

use \Closure;
use \Yabacon\Paystack\Contracts\RouteInterface;

/**
 * Router
 * Insert description here
 *
 * @category
 * @package
 * @author
 * @copyright
 * @license
 * @version
 * @link
 * @see
 * @since
 */
class Router
{

    private $route;
    private $route_class;
    private $secret_key;
    private $methods;
    private $use_guzzle=false;

    const ID_KEY = 'id';
    const PAYSTACK_API_ROOT = 'https://api.paystack.co';

    /**
 * moveArgsToSentargs
 * Insert description here
 *
 * @param $interface
 * @param $payload
 * @param $sentargs
 *
 * @return
 *
 * @access
 * @static
 * @see
 * @since
 */
    private function moveArgsToSentargs(
        $interface,
        &$payload,
        &$sentargs
    ) {



        // check if interface supports args
        if (array_key_exists(RouteInterface:: ARGS_KEY, $interface)) {
            // to allow args to be specified in the payload, filter them out and put them in sentargs
            $sentargs = (!$sentargs) ? [ ] : $sentargs; // Make sure $sentargs is not null
            $args = $interface[RouteInterface::ARGS_KEY];
            while (list($key, $value) = $this->altEach($payload)) {
                // check that a value was specified
                // with a key that was expected as an arg
                if (in_array($key, $args)) {
                    $sentargs[$key] = $value;
                    unset($payload[$key]);
                }
            }
        }
    }

    /**
 * putArgsIntoEndpoint
 * Insert description here
 *
 * @param $endpoint
 * @param $sentargs
 *
 * @return
 *
 * @access
 * @static
 * @see
 * @since
 */
    private function putArgsIntoEndpoint(&$endpoint, $sentargs)
    {
        // substitute sentargs in endpoint
        while (list($key, $value) = $this->altEach($sentargs)) {
            $endpoint = str_replace('{' . $key . '}', $value, $endpoint);
        }
    }

    /**
 * callViaCurl
 * Insert description here
 *
 * @param $interface
 * @param $payload
 * @param $sentargs
 *
 * @return
 *
 * @access
 * @static
 * @see
 * @since
 */
    private function callViaCurl($interface, $payload = [ ], $sentargs = [ ])
    {
 

        $endpoint = Router::PAYSTACK_API_ROOT . $interface[RouteInterface::ENDPOINT_KEY];
        $method = $interface[RouteInterface::METHOD_KEY];

        $this->moveArgsToSentargs($interface, $payload, $sentargs);
        $this->putArgsIntoEndpoint($endpoint, $sentargs);
 
        $headers = ["Authorization"=>"Bearer " . $this->secret_key ];
        $body = '';
        if (($method === RouteInterface::POST_METHOD)
            || ($method === RouteInterface::PUT_METHOD)
        ) {
            $headers["Content-Type"] = "application/json";
            $body = json_encode($payload);
        } elseif ($method === RouteInterface::GET_METHOD) {
            $endpoint = $endpoint . '?' . http_build_query($payload);
        }
        // Use Guzzle if found, else use Curl
        if ($this->use_guzzle && class_exists('\\GuzzleHttp\\Client') && class_exists('\\GuzzleHttp\\Psr7\\Request')) {
            $request = new \GuzzleHttp\Psr7\Request(strtoupper($method), $endpoint, $headers, $body);
            $client = new \GuzzleHttp\Client();
            try {
                $response = $client->send($request);
            } catch (\Exception $e) {
                if ($e->hasResponse()) {
                    $response = $e->getResponse();
                } else {
                    throw $e;
                }
            }
            return $response;
        } else {
            //open connection
        
            $ch = \curl_init();
            // set url
            \curl_setopt($ch, \CURLOPT_URL, $endpoint);
 
            if ($method === RouteInterface::POST_METHOD || $method === RouteInterface::PUT_METHOD) {
                ($method === RouteInterface:: POST_METHOD) && \curl_setopt($ch, \CURLOPT_POST, true);
                ($method === RouteInterface ::PUT_METHOD) && \curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");

                \curl_setopt($ch, \CURLOPT_POSTFIELDS, $body);
            }
            //flatten the headers
            $flattened_headers = [];
            while (list($key, $value) = $this->altEach($headers)) {
                $flattened_headers[] = $key . ": " . $value;
            }
            \curl_setopt($ch, \CURLOPT_HTTPHEADER, $flattened_headers);
            \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1);

            // Make sure CURL_SSLVERSION_TLSv1_2 is defined as 6
            // Curl must be able to use TLSv1.2 to connect
            // to Paystack servers
            
            if (!defined('CURL_SSLVERSION_TLSV1_2')) {
                define('CURL_SSLVERSION_TLSV1_2', 6);
            }
            curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSV1_2);

            $response = \curl_exec($ch);
            
            if (\curl_errno($ch)) {   // should be 0
                // curl ended with an error
                $cerr = \curl_error($ch);
                \curl_close($ch);
                throw new \Exception("Curl failed with response: '" . $cerr . "'.");
            }

            // Then, after your \curl_exec call:
            $resp = json_decode($response);
            //close connection
            \curl_close($ch);

            if (!$resp->status) {
                throw new \Exception("Paystack Request failed with response: '" . $resp->message . "'.");
            }

            return $resp;
        }

    }
    
    /**
 * __call
 * Insert description here
 *
 * @param $methd
 * @param $sentargs
 *
 * @return
 *
 * @access
 * @static
 * @see
 * @since
 */
    public function __call($methd, $sentargs)
    {
        $method = ($methd === 'list' ? 'getList' : $methd );
        if (array_key_exists($method, $this->methods) && is_callable($this->methods[$method])) {
            return call_user_func_array($this->methods[$method], $sentargs);
        } else {
            // User attempted to call a function that does not exist
            throw new \Exception('Function "' . $method . '" does not exist for "' . $this->route . '".');
        }
    }

    /**
 * A magic resource object that can make method calls to API
 *
 * @param $route
 * @param $paystackObj - A Yabacon\Paystack Object
 */
    public function __construct($route, $paystackObj)
    {
        $this->route = strtolower($route);
        $this->route_class = 'Yabacon\\Paystack\\Routes\\' . ucwords($route);
        $this->secret_key = $paystackObj->secret_key;
        $this->use_guzzle = $paystackObj->use_guzzle;

        $mets = get_class_methods($this->route_class);
        if (empty($mets)) {
            throw new \InvalidArgumentException('Class "' . $this->route . '" does not exist.');
        }
        // add methods to this object per method, except root
        foreach ($mets as $mtd) {
            if ($mtd === 'root') {
                // skip root method
                continue;
            }
            /**
 * array
 * Insert description here
 *
 * @param $params
 * @param array
 * @param $sentargs
 *
 * @return
 *
 * @access
 * @static
 * @see
 * @since
 */
            $mtdFunc = function (
                array $params = [ ],
                array $sentargs = [ ]
            ) use ($mtd) {
                $interface = call_user_func($this->route_class . '::' . $mtd);
                // TODO: validate params and sentargs against definitions
                return $this->callViaCurl($interface, $params, $sentargs);
            };
            $this->methods[$mtd] = \Closure::bind($mtdFunc, $this, get_class());
        }
    }


    public function altEach(&$data)

    {

        $key = key($data);

        $ret = ($key === null)? false: [$key, current($data), "key" => $key, "value" => current($data)];

        next($data);

        return $ret;

    }
}