Completed
Push — master ( 02addd...f1621a )
by Alessandro
11:52 queued 02:31
created

Client::prepareRequest()   C

Complexity

Conditions 7
Paths 64

Size

Total Lines 35
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 26
CRAP Score 7.0024

Importance

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