Test Setup Failed
Push — master ( 703a7a...3ebce0 )
by Syed Abidur
11:53
created

Client::prepareCurlOptions()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 55
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 38
c 2
b 0
f 0
nc 10
nop 1
dl 0
loc 55
rs 8.6897

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Sarahman\SmsService;
4
5
use Exception;
6
use GuzzleHttp\Psr7\Response as GuzzleResponse;
7
use Illuminate\Support\Facades\Config;
8
use Illuminate\Support\Facades\Log;
9
use Illuminate\Support\Facades\Validator;
10
use Sarahman\HttpRequestApiLog\Traits\WritesHttpLogs;
11
use Sarahman\SmsService\Interfaces\NeedsAuthenticationInterface;
12
use Sarahman\SmsService\Interfaces\ProviderInterface;
13
14
class Client
15
{
16
    use WritesHttpLogs;
17
18
    const PROVIDER_BANGLALINK = Providers\Banglalink::class;
19
    const PROVIDER_BD_WEB_HOST_24 = Providers\BdWebHost24::class;
20
    const PROVIDER_BOOM_CAST = Providers\BoomCast::class;
21
    const PROVIDER_ELITBUZZ = Providers\Elitbuzz::class;
22
    const PROVIDER_GRAMEENPHONE = Providers\Grameenphone::class;
23
    const PROVIDER_NOVOCOM = Providers\Novocom::class;
24
    const PROVIDER_PAYSTATION = Providers\Paystation::class;
25
    const PROVIDER_ROBI = Providers\Robi::class;
26
    const PROVIDER_SSL = Providers\Ssl::class;
27
    const PROVIDER_SSL_PLUS = Providers\SslPlus::class;
28
    const PROVIDER_VALUE_FIRST = Providers\ValueFirst::class;
29
30
    private $provider;
31
32
    public function __construct(ProviderInterface $provider)
33
    {
34
        $this->provider = $provider;
35
        $this->enableLogging = Config::get('sms-service-with-bd-providers::config.enable_api_call_logging', false);
36
    }
37
38
    /**
39
     * Return a SMS provider according to the given provider name.
40
     *
41
     * @param string $providerName
42
     * @param array  $config
43
     * @param string $url
44
     *
45
     * @return ProviderInterface
46
     */
47
    public static function getProvider($providerName = self::PROVIDER_SSL, array $config = [], $url = null)
48
    {
49
        switch ($providerName) {
50
            case self::PROVIDER_BANGLALINK:
51
            case self::PROVIDER_BD_WEB_HOST_24:
52
            case self::PROVIDER_BOOM_CAST:
53
            case self::PROVIDER_ELITBUZZ:
54
            case self::PROVIDER_GRAMEENPHONE:
55
            case self::PROVIDER_NOVOCOM:
56
            case self::PROVIDER_PAYSTATION:
57
            case self::PROVIDER_ROBI:
58
            case self::PROVIDER_SSL:
59
            case self::PROVIDER_SSL_PLUS:
60
            case self::PROVIDER_VALUE_FIRST:
61
                return new $providerName($config, $url);
62
63
            default:
64
                throw new Exception('Invalid SMS provider name is given.');
65
        }
66
    }
67
68
    public function send($recipients, $message, array $params = [])
69
    {
70
        $log = ['sent' => [], 'failed' => []];
71
        is_array($recipients) || $recipients = [$recipients];
72
73
        foreach ($recipients as $recipient) {
74
            $options = ['url' => $this->provider->getUrl()];
75
76
            try {
77
                if (!$data = $this->provider->mapParams($recipient, $message, $params)) {
78
                    throw new Exception(json_encode('Failed to map the params.'), 422);
79
                }
80
81
                $data = array_merge($this->provider->getConfig(), $data);
82
                $validator = Validator::make($data, $this->provider->getValidationRules());
83
84
                if ($validator->fails()) {
85
                    throw new Exception(json_encode($validator->messages()->all()), 422);
86
                }
87
88
                $options += $this->prepareCurlOptions($data);
89
                $response = $this->provider->parseResponse($this->executeWithCurl($options));
90
91
                if (!$response->getStatus()) {
92
                    throw new Exception($response->getResponseString(), 500);
93
                }
94
95
                $log['sent'][$recipient] = $response->toArray();
96
97
                $this->log('POST', $options['url'], $options, new GuzzleResponse(200, [], $response->getResponseString()));
98
            } catch (Exception $e) {
99
                $errorCode = $e->getCode() >= 100 ? $e->getCode() : 500;
100
                $errorMessage = 422 != $errorCode ? $e->getMessage() : json_decode($e->getMessage(), true);
101
                $log['failed'][$recipient] = (new Response(false, $errorMessage))->toArray();
102
103
                $this->log('POST', $options['url'], $options, new GuzzleResponse($errorCode, [], $errorMessage));
104
            }
105
        }
106
107
        return $this->getSummaryWithLogs($log);
108
    }
109
110
    public function sendWithFallback($recipients, $message, array $params = [])
111
    {
112
        $log = ['sent' => [], 'failed' => []];
113
        is_array($recipients) || $recipients = [$recipients];
114
115
        foreach ($recipients as $recipient) {
116
            $options = ['url' => $this->provider->getUrl()];
117
118
            try {
119
                if (!$data = $this->provider->mapParams($recipient, $message, $params)) {
120
                    throw new Exception(json_encode('Failed to map the params.'), 422);
121
                }
122
123
                $data = array_merge($this->provider->getConfig(), $data);
124
                $validator = Validator::make($data, $this->provider->getValidationRules());
125
126
                if ($validator->fails()) {
127
                    throw new Exception(json_encode($validator->messages()->all()), 422);
128
                }
129
130
                $options += $this->prepareCurlOptions($data);
131
132
                try {
133
                    $response = $this->executeWithCurl($options);
134
                } catch (Exception $e) {
135
                    $log['failed'][$recipient] = (new Response(false, $e->getMessage()))->toArray();
136
                    $response = '';
137
                }
138
139
                $response = $this->provider->parseResponse($response);
140
141
                if (!$response->getStatus()) {
142
                    $this->log('POST', $options['url'], $options, new GuzzleResponse(500, [], $response->getResponseString()));
143
144
                    //Resend sms
145
                    Log::info('SMS sending failed response!');
146
147
                    try {
148
                        $response = $this->provider->parseResponse($this->executeWithCurl($options));
149
                        Log::info('Second try of sending SMS', $response);
150
151
                        if (!$response->getStatus()) {
152
                            throw new Exception($response->getResponseString(), 500);
153
                        }
154
                    } catch (Exception $e) {
155
                        Log::error('Curl error response: '.$e->getMessage());
156
157
                        throw $e;
158
                    }
159
                }
160
161
                $log['sent'][$recipient] = $response->toArray();
162
163
                $this->log('POST', $options['url'], $options, new GuzzleResponse(200, [], $response->getResponseString()));
164
            } catch (Exception $e) {
165
                $errorCode = $e->getCode() >= 100 ? $e->getCode() : 500;
166
                $errorMessage = 422 != $errorCode ? $e->getMessage() : json_decode($e->getMessage(), true);
167
                $log['failed'][$recipient] = (new Response(false, $errorMessage))->toArray();
168
169
                $this->log('POST', $options['url'], $options, new GuzzleResponse($errorCode, [], $errorMessage));
170
            }
171
        }
172
173
        return $this->getSummaryWithLogs($log);
174
    }
175
176
    /**
177
     * Prepare the curl options array according to the given data.
178
     *
179
     * @param array $data
180
     *
181
     * @return array
182
     */
183
    private function prepareCurlOptions(array $data)
184
    {
185
        $options = [
186
            'timeout' => 30,
187
        ];
188
189
        switch(get_class($this->provider)) {
190
            case self::PROVIDER_GRAMEENPHONE:
191
            case self::PROVIDER_NOVOCOM:
192
                $options += [
193
                    'httpheader' => ['Content-Type: application/json'],
194
                    'post'       => 1,
195
                    'postfields' => json_encode($data),
196
                ];
197
                break;
198
199
            case self::PROVIDER_PAYSTATION:
200
                $options += [
201
                    'httpheader' => [
202
                        'Content-Type: application/json',
203
                        'Accept: application/json',
204
                        'user_id:'.$data['user_id'],
205
                        'password:'.$data['password'],
206
                    ],
207
                    'post'       => 1,
208
                    'postfields' => json_encode($data),
209
                ];
210
                break;
211
212
            case self::PROVIDER_SSL_PLUS:
213
                $encodedData = json_encode($data);
214
                $options += [
215
                    'httpheader'    => [
216
                        'Content-Type: application/json',
217
                        'Content-Length: '.strlen($encodedData),
218
                        'Accept: application/json',
219
                    ],
220
                    'customrequest' => 'POST',
221
                    'post'          => 1,
222
                    'postfields'    => $encodedData,
223
                ];
224
                break;
225
226
            default:
227
                $options += [
228
                    'post'       => count($data),
229
                    'postfields' => http_build_query($data),
230
                ];
231
        }
232
233
        if ($this->provider instanceof NeedsAuthenticationInterface) {
234
            $options['httpheader'][] = 'Authorization: Bearer '.$this->provider->getAccessToken();
0 ignored issues
show
Bug introduced by
The method getAccessToken() does not exist on Sarahman\SmsService\Interfaces\ProviderInterface. It seems like you code against a sub-type of Sarahman\SmsService\Interfaces\ProviderInterface such as Sarahman\SmsService\Providers\ValueFirst. ( Ignorable by Annotation )

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

234
            $options['httpheader'][] = 'Authorization: Bearer '.$this->provider->/** @scrutinizer ignore-call */ getAccessToken();
Loading history...
235
        }
236
237
        return $options;
238
    }
239
240
    /**
241
     * Execute the Curl request according to the given curl options.
242
     *
243
     * @param array $options
244
     *
245
     * @return string
246
     */
247
    private function executeWithCurl(array $options)
248
    {
249
        $curlOptions = [];
250
        isset($options['returntransfer']) || $options['returntransfer'] = true;
251
252
        foreach ($options as $key => $value) {
253
            $option = 'CURLOPT_'.strtoupper($key);
254
            $curlOptions[constant($option)] = $value;
255
        }
256
257
        $ch = curl_init();
258
259
        curl_setopt_array($ch, $curlOptions);
260
261
        $response = curl_exec($ch);
262
263
        if ($response != true) {
264
            $errorNumber = curl_errno($ch);
265
            $eMsg = 'cURL Error # '.$errorNumber.' | cURL Error Message: '.curl_error($ch);
266
267
            curl_close($ch);
268
269
            if (60 == $errorNumber) {
270
                $curlOptions[constant('CURLOPT_SSL_VERIFYPEER')] = false;
271
                $ch = curl_init();
272
273
                curl_setopt_array($ch, $curlOptions);
274
275
                $response = curl_exec($ch);
276
277
                if ($response != true) {
278
                    $eMsg = 'cURL Error # '.curl_errno($ch).' | cURL Error Message: '.curl_error($ch);
279
280
                    curl_close($ch);
281
282
                    throw new Exception($eMsg);
283
                }
284
            } else {
285
                throw new Exception($eMsg);
286
            }
287
        }
288
289
        curl_close($ch);
290
291
        return (string) $response;
292
    }
293
294
    private function getSummaryWithLogs(array $log)
295
    {
296
        $sent = count($log['sent']);
297
        $failed = count($log['failed']);
298
299
        return [
300
            'summary' => [
301
                'sent'   => $sent,
302
                'failed' => $failed,
303
                'total'  => $sent + $failed,
304
            ],
305
            'log'     => $log,
306
        ];
307
    }
308
}
309