Completed
Push — master ( ec0178...c6402c )
by Alessandro
04:17
created

Client::prepareRequest()   C

Complexity

Conditions 7
Paths 64

Size

Total Lines 35
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 7.0027

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 25
cts 26
cp 0.9615
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 26
nc 64
nop 1
crap 7.0027
1
<?php
2
3
namespace Fazland\SkebbyRestClient\Client;
4
5
use Fazland\SkebbyRestClient\Constant\Charsets;
6
use Fazland\SkebbyRestClient\Constant\EncodingSchemas;
7
use Fazland\SkebbyRestClient\Constant\Endpoints;
8
use Fazland\SkebbyRestClient\Constant\Recipients;
9
use Fazland\SkebbyRestClient\Constant\SendMethods;
10
use Fazland\SkebbyRestClient\Constant\ValidityPeriods;
11
use Fazland\SkebbyRestClient\DataStructure\Response;
12
use Fazland\SkebbyRestClient\DataStructure\Sms;
13
use Fazland\SkebbyRestClient\Exception\NoRecipientsSpecifiedException;
14
use libphonenumber\NumberParseException;
15
use libphonenumber\PhoneNumberFormat;
16
use libphonenumber\PhoneNumberUtil;
17
use Symfony\Component\OptionsResolver\OptionsResolver;
18
19
/**
20
 * @author Massimiliano Braglia <[email protected]>
21
 */
22
class Client
23
{
24
    /**
25
     * @var array
26
     */
27
    private $config;
28
29
    /**
30
     * @param array $options
31
     */
32 8
    public function __construct(array $options)
33
    {
34 8
        $resolver = new OptionsResolver();
35
36 8
        $this->configureOptions($resolver);
37 8
        $this->config = $resolver->resolve($options);
38 8
    }
39
40
    /**
41
     * Send an SMS
42
     *
43
     * @param Sms $sms
44
     *
45
     * @return Response[]
46
     *
47
     * @throws NoRecipientsSpecifiedException
48
     */
49 8
    public function send(Sms $sms)
50
    {
51 8
        if (! $sms->hasRecipients()) {
52 1
            throw new NoRecipientsSpecifiedException();
53
        }
54
55 7
        $messages = [];
56
57 7
        $recipients = $sms->getRecipients();
58 7
        foreach (array_chunk($recipients, Recipients::MAX) as $chunk) {
59 7
            $message = clone $sms;
60
            $message
61 7
                ->setRecipients($chunk)
62 7
                ->clearRecipientVariables()
63
            ;
64
65 7
            foreach ($chunk as $recipient) {
66 7
                if (! isset($sms->getRecipientVariables()[$recipient])) {
67 5
                    continue;
68
                }
69
70 3
                foreach ($sms->getRecipientVariables()[$recipient] as $variable => $value) {
71 3
                    $message->addRecipientVariable($recipient, $variable, $value);
72 3
                }
73 7
            }
74
75 7
            $messages[] = $message;
76 7
        }
77
78 7
        $responses = [];
79 7
        foreach ($messages as $message) {
80 7
            $request = $this->prepareRequest($message);
81
82 7
            $responses[] = $this->executeRequest($request);
83 5
        }
84
85 5
        return $responses;
86
    }
87
88
    /**
89
     * Configure default options for client.
90
     *
91
     * It takes required options username, password, sender and method.
92
     * validity_period MUST be a \DateInterval object if set
93
     * delivery_start MUST be a \DateTime object if set
94
     *
95
     * @param OptionsResolver $resolver
96
     */
97 8
    private function configureOptions(OptionsResolver $resolver)
98
    {
99
        $resolver
100 8
            ->setRequired([
101 8
                'username',
102 8
                'password',
103 8
                'sender',
104 8
                'method',
105 8
            ])
106 8
            ->setDefaults([
107 8
                'delivery_start' => null,
108 8
                'charset' => Charsets::UTF8,
109 8
                'validity_period' => \DateInterval::createFromDateString('2800 minutes'),
110 8
                'encoding_schema' => EncodingSchemas::NORMAL,
111 8
                'endpoint_uri' => Endpoints::REST_HTTPS,
112 8
            ])
113 8
            ->setAllowedTypes('username', 'string')
114 8
            ->setAllowedTypes('password', 'string')
115 8
            ->setAllowedTypes('sender', 'string')
116 8
            ->setAllowedTypes('method', 'string')
117 8
            ->setAllowedTypes('delivery_start', ['null', 'DateTime'])
118 8
            ->setAllowedTypes('validity_period', ['null', 'DateInterval'])
119 8
            ->setAllowedTypes('encoding_schema', 'string')
120 8
            ->setAllowedTypes('charset', 'string')
121 8
            ->setAllowedTypes('endpoint_uri', 'string')
122 8
            ->setAllowedValues('method', [
123 8
                SendMethods::CLASSIC,
124 8
                SendMethods::CLASSIC_PLUS,
125 8
                SendMethods::BASIC,
126 8
                SendMethods::TEST_CLASSIC,
127 8
                SendMethods::TEST_CLASSIC_PLUS,
128 8
                SendMethods::TEST_BASIC,
129 8
            ])
130
            ->setAllowedValues('validity_period', function (\DateInterval $value) {
131 8
                return $value->i >= ValidityPeriods::MIN && $value->i <= ValidityPeriods::MAX;
132 8
            })
133 8
            ->setAllowedValues('encoding_schema', [
134 8
                EncodingSchemas::NORMAL,
135 8
                EncodingSchemas::UCS2,
136 8
            ])
137 8
            ->setAllowedValues('charset', [
138 8
                Charsets::ISO_8859_1,
139 8
                Charsets::UTF8,
140 8
            ])
141
        ;
142 8
    }
143
144
    /**
145
     * @param Sms $sms
146
     *
147
     * @return array
148
     */
149 7
    private function prepareRequest(Sms $sms)
150
    {
151 7
        $sender_string = null;
152 7
        $sender_number = null;
153
        try {
154 7
            $sender_number = $this->normalizePhoneNumber($this->config['sender']);
155 7
        } catch (NumberParseException $e) {
156
            $sender_string = substr($this->config['sender'], 0, 11);
157
        }
158
159 7
        $deliveryStart = $sms->getDeliveryStart() ?: $this->config['delivery_start'];
160 7
        $validityPeriod = $sms->getValidityPeriod() ?: $this->config['validity_period'];
161
162
        $request = [
163 7
            'username' => $this->config['username'],
164 7
            'password' => $this->config['password'],
165 7
            'method' => $this->config['method'],
166 7
            'sender_number' => $sender_number,
167 7
            'sender_string' => $sender_string,
168 7
            'recipients' => $this->prepareRecipients($sms),
169 7
            'text' => str_replace(' ', '+', $sms->getText()),
170 7
            'user_reference' => $sms->getUserReference(),
171 7
            'delivery_start' => $deliveryStart ? urlencode($deliveryStart->format(\DateTime::RFC2822)) : null,
172 7
            'validity_period' => $validityPeriod ? $validityPeriod->i : null,
173 7
            'encoding_scheme' => $this->config['encoding_schema'],
174 7
            'charset' => urlencode($this->config['charset']),
175 7
        ];
176
177 7
        $serializedRequest = [];
178 7
        foreach ($request as $key => $value) {
179 7
            $serializedRequest[] = "$key=$value";
180 7
        }
181
182 7
        return implode('&', $serializedRequest);
183
    }
184
185
    /**
186
     * @param Sms $sms
187
     *
188
     * @return string
189
     */
190 7
    private function prepareRecipients(Sms $sms)
191
    {
192 7
        $recipients = $sms->getRecipients();
193
194 7
        if (! $sms->hasRecipientVariables()) {
195 4
            $recipients = array_map([$this, 'normalizePhoneNumber'], $recipients);
196
197 4
            return json_encode($recipients);
198
        }
199
200 3
        $recipientVariables = $sms->getRecipientVariables();
201
202 3
        return json_encode(array_map(function ($recipient) use ($recipientVariables) {
203 3
            $targetVariables = [];
204 3
            if (isset($recipientVariables[$recipient])) {
205 3
                $targetVariables = $recipientVariables[$recipient];
206 3
            }
207
208 3
            return array_merge(['recipient' => $this->normalizePhoneNumber($recipient)], $targetVariables);
209 3
        }, $recipients));
210
    }
211
212
    /**
213
     * @param string $phoneNumber
214
     *
215
     * @return string
216
     *
217
     * @throws NumberParseException
218
     */
219 7
    private function normalizePhoneNumber($phoneNumber)
220
    {
221 7
        $utils = PhoneNumberUtil::getInstance();
222 7
        $parsed = $utils->parse(preg_replace('/^00/', '+', $phoneNumber), null);
223
224 7
        $phoneNumber = $utils->format($parsed, PhoneNumberFormat::E164);
225
226 7
        return substr($phoneNumber, 1);
227
    }
228
229
    /**
230
     * @param string $request
231
     *
232
     * @return Response
233
     */
234 7
    private function executeRequest($request)
235
    {
236 7
        $curl = curl_init();
237
238 7
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
239 7
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
240 7
        curl_setopt($curl, CURLOPT_TIMEOUT, 60);
241 7
        curl_setopt($curl, CURLOPT_POST, 1);
242 7
        curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
243 7
        curl_setopt($curl, CURLOPT_URL, $this->config['endpoint_uri']);
244
245 7
        $response = curl_exec($curl);
246
247 7
        curl_close($curl);
248
249 7
        return new Response($response);
250
    }
251
}
252