Issues (13)

src/MpesaApiClient.php (1 issue)

Labels
Severity
1
<?php
2
3
namespace Starnerz\LaravelDaraja;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\Exception\ClientException;
7
use GuzzleHttp\Exception\ServerException;
8
use Illuminate\Support\Facades\Route;
9
use Starnerz\LaravelDaraja\Exceptions\MpesaApiRequestException;
10
use Starnerz\LaravelDaraja\Logging\Log;
11
12
class MpesaApiClient
13
{
14
    /**
15
     * Guzzle client initialization.
16
     *
17
     * @var Client
18
     */
19
    protected $client;
20
21
    /**
22
     * Safaricom MPESA APIs application consumer key.
23
     *
24
     * @var string
25
     */
26
    protected $consumerKey;
27
28
    /**
29
     * Safaricom MPESA APIs application consumer secret.
30
     *
31
     * @var string
32
     */
33
    protected $consumerSecret;
34
35
    /**
36
     * Access token generated by Safaricom MPESA APIs.
37
     *
38
     * @var string
39
     */
40
    protected $accessToken;
41
42
    /**
43
     * Identifier organization Map on Safaricom MPESA APIs.
44
     *
45
     * @var array
46
     */
47
    protected $identifier = [
48
        'msisdn' => '1', // MSISDN
49
        'till' => '2', // Till Number
50
        'paybill' => '4', // Shortcode
51
    ];
52
53
    /**
54
     * Base URL end points for the Safaricom APIs.
55
     *
56
     * @var array
57
     */
58
    protected $base_url = [
59
        'sandbox' => 'https://sandbox.safaricom.co.ke',
60
        'live' => 'https://api.safaricom.co.ke',
61
    ];
62
63
    /**
64
     * Make the initializations required to make calls to the Safaricom MPESA APIs
65
     * and throw the necessary exception if there are any missing required
66
     * configurations.
67
     */
68
    public function __construct()
69
    {
70
        $this->validateConfigurations();
71
72
        $mode = config('laravel-daraja.mode');
73
74
        $options = [
75
            'base_uri' => $this->base_url[$mode],
76
            'verify' => $mode === 'sandbox' ? false : true,
77
        ];
78
79
        if (config('laravel-daraja.logs.enabled')) {
80
            $options = Log::enable($options);
81
        }
82
83
        $this->client = new Client($options);
0 ignored issues
show
It seems like $options can also be of type integer; however, parameter $config of GuzzleHttp\Client::__construct() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

83
        $this->client = new Client(/** @scrutinizer ignore-type */ $options);
Loading history...
84
        $this->consumerKey = config('laravel-daraja.consumer_key');
85
        $this->consumerSecret = config('laravel-daraja.consumer_secret');
86
        $this->getAccessToken();
87
    }
88
89
    /**
90
     * Check if it contains a route name and return full route or
91
     * return the string assuming its a full URL.
92
     *
93
     * @param $urlConfig
94
     * @return string
95
     */
96
    protected function setUrl($urlConfig)
97
    {
98
        return Route::has($urlConfig) ? route($urlConfig) : $urlConfig;
99
    }
100
101
    /**
102
     * Get access token from Safaricom MPESA APIs.
103
     *
104
     * @return mixed
105
     */
106
    protected function getAccessToken()
107
    {
108
        // Set the auth option
109
        $options = [
110
            'auth' => [
111
                $this->consumerKey,
112
                $this->consumerSecret,
113
            ],
114
        ];
115
116
        $accessTokenDetails = $this->call('oauth/v1/generate?grant_type=client_credentials', $options, 'GET');
117
        $this->accessToken = $accessTokenDetails->access_token;
118
    }
119
120
    /**
121
     * Validate configurations.
122
     */
123
    protected function validateConfigurations()
124
    {
125
        // Validate keys
126
        if (empty(config('laravel-daraja.consumer_key'))) {
127
            throw new \InvalidArgumentException('Consumer key has not been set.');
128
        }
129
        if (empty(config('laravel-daraja.consumer_secret'))) {
130
            throw new \InvalidArgumentException('Consumer secret has not been set');
131
        }
132
    }
133
134
    /**
135
     * Generate encrypted security credential.
136
     *
137
     * @param $plaintext
138
     * @return string
139
     *
140
     * @internal param null|string $password
141
     */
142
    protected function securityCredential($plaintext)
143
    {
144
        $publicKey = file_get_contents(__DIR__.'/../cert.cer');
145
146
        openssl_public_encrypt($plaintext, $encrypted, $publicKey, OPENSSL_PKCS1_PADDING);
147
148
        return base64_encode($encrypted);
149
    }
150
151
    /**
152
     * Make API calls to Safaricom MPESA APIs.
153
     *
154
     * @param  string  $url
155
     * @param  array  $options
156
     * @param  string  $method
157
     * @return mixed
158
     *
159
     * @throws MpesaApiRequestException
160
     */
161
    protected function call($url, $options = [], $method = 'POST')
162
    {
163
        if (isset($this->accessToken)) {
164
            $options['headers'] = ['Authorization' => 'Bearer '.$this->accessToken];
165
        }
166
167
        try {
168
            $response = $this->client->request($method, $url, $options);
169
170
            $stream = $response->getBody();
171
            $stream->rewind();
172
            $content = $stream->getContents();
173
174
            return json_decode($content);
175
        } catch (ServerException $e) {
176
            $response = json_decode($e->getResponse()->getBody()->getContents());
177
            if (isset($response->Envelope)) {
178
                $message = 'Safaricom APIs: '.$response->Envelope->Body->Fault->faultstring;
179
                throw new MpesaApiRequestException($message, $e->getCode());
180
            }
181
            throw new MpesaApiRequestException('Safaricom APIs: '.$response->errorMessage, $e->getCode());
182
        } catch (ClientException $e) {
183
            $response = json_decode($e->getResponse()->getBody()->getContents());
184
            throw new MpesaApiRequestException('Safaricom APIs: '
185
                .$response->errorMessage, $e->getCode());
186
        }
187
    }
188
}
189