MicrosoftTranslator::speak()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 4
crap 1
1
<?php
2
/**
3
 * This file is part of the badams\MicrosoftTranslator library
4
 *
5
 * @license http://opensource.org/licenses/MIT
6
 * @link https://github.com/badams/microsoft-translator
7
 * @package badams/microsoft-translator
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace badams\MicrosoftTranslator;
14
15
use badams\MicrosoftTranslator\Exceptions\ArgumentException;
16
use badams\MicrosoftTranslator\Exceptions\AuthException;
17
use badams\MicrosoftTranslator\Exceptions\QuotaExceededException;
18
use badams\MicrosoftTranslator\Exceptions\TokenExpiredException;
19
use badams\MicrosoftTranslator\Exceptions\TranslatorException;
20
use badams\MicrosoftTranslator\Methods\Detect;
21
use badams\MicrosoftTranslator\Methods\GetLanguageNames;
22
use badams\MicrosoftTranslator\Methods\GetLanguagesForSpeak;
23
use badams\MicrosoftTranslator\Methods\GetLanguagesForTranslate;
24
use badams\MicrosoftTranslator\Methods\GetTranslations;
25
use badams\MicrosoftTranslator\Methods\GetTranslationsArray;
26
use badams\MicrosoftTranslator\Methods\Speak;
27
use badams\MicrosoftTranslator\Methods\Translate;
28
use badams\MicrosoftTranslator\Responses\GetTranslationsResponse;
29
use GuzzleHttp\Exception\RequestException;
30
31
/**
32
 * Class MicrosoftTranslator
33
 * @package badams\MicrosoftTranslator
34
 */
35
class MicrosoftTranslator
36
{
37
    /**
38
     *
39
     */
40
    const AUTH_URL = 'https://datamarket.accesscontrol.windows.net/v2/OAuth2-13';
41
42
    /**
43
     *
44
     */
45
    const BASE_URL = 'http://api.microsofttranslator.com/V2/Http.svc/';
46
47
    /**
48
     * @var \GuzzleHttp\ClientInterface
49
     */
50
    private $http;
51
52
    /**
53
     * @var string
54
     */
55
    private $scope = 'http://api.microsofttranslator.com';
56
57
    /**
58
     * @var string
59
     */
60
    private $grantType = 'client_credentials';
61
62
    /**
63
     * @var string
64
     */
65
    private $clientId;
66
67
    /**
68
     * @var string
69
     */
70
    private $clientSecret;
71
72
    /**
73
     * @var string
74
     */
75
    private $accessToken;
76
77
    /**
78
     * MicrosoftTranslator constructor.
79
     */
80 54
    public function __construct(\GuzzleHttp\ClientInterface $httpClient = null)
81
    {
82 54
        if (is_null($httpClient)) {
83 3
            $httpClient = new \GuzzleHttp\Client();
84 3
        }
85
86 54
        $this->http = $httpClient;
87 54
    }
88
89
    /**
90
     * @param $id
91
     * @param $secret
92
     */
93 39
    public function setClient($id, $secret)
94
    {
95 39
        $this->clientId = $id;
96 39
        $this->clientSecret = $secret;
97 39
    }
98
99
    /**
100
     * @return mixed
101
     * @throws AuthException
102
     */
103 48
    private function getAccessToken()
104 18
    {
105 48
        if (!$this->accessToken) {
106 48
            $params = array_merge([
107 48
                'grant_type' => $this->grantType,
108 48
                'scope' => $this->scope,
109 48
                'client_id' => $this->clientId,
110 48
                'client_secret' => $this->clientSecret
111 48
            ]);
112
113
            try {
114 48
                $response = $this->http->post(self::AUTH_URL, ['body' => $params]);
115 45
                $result = json_decode((string)$response->getBody());
116 48
            } catch (RequestException $e) {
117 3
                $result = json_decode((string)$e->getResponse()->getBody());
118 3
                throw new AuthException($result->error_description);
119 3
            }
120
121 45
            $this->accessToken = $result->access_token;
122 45
        }
123
124 45
        return $this->accessToken;
125
    }
126
127
    /**
128
     * @param ApiMethodInterface $method
129
     * @return \GuzzleHttp\Message\Request|\GuzzleHttp\Message\RequestInterface
130
     * @throws AuthException
131
     */
132 45
    private function createRequest(ApiMethodInterface $method)
133
    {
134 45
        $reflection = new \ReflectionClass($method);
135
136 45
        return $this->http->createRequest(
137 45
            $method->getRequestMethod(),
138 45
            self::BASE_URL . $reflection->getShortName(),
139 45
            array_merge([
140 45
                'exceptions' => false,
141
                'headers' => [
142 45
                    'Authorization' => 'Bearer ' . $this->getAccessToken(),
143 45
                    'Content-Type' => 'text/xml',
144 45
                ],
145
146 45
            ], $method->getRequestOptions())
147 45
        );
148
    }
149
150
    /**
151
     * @param ApiMethodInterface $method
152
     * @return mixed
153
     * @throws ArgumentException
154
     * @throws QuotaExceededException
155
     * @throws TranslatorException
156
     */
157 45
    private function execute(ApiMethodInterface $method)
158
    {
159 45
        $response = $this->http->send($this->createRequest($method));
160
161 45
        if ($response->getStatusCode() != 200) {
162
            try {
163 12
                $message = strip_tags($response->getBody());
164 12
                $this->assertNoArgumentException($message);
165 6
                $this->assertNoTranslateExceptionAndZeroBalance($message);
166 12
            } catch (TokenExpiredException $e) {
167 3
                $this->accessToken = null;
168 3
                return $this->execute($method);
169
            }
170
171 3
            throw new TranslatorException($response->getBody());
172
        }
173
174 36
        return $method->processResponse($response);
175
    }
176
177
    /**
178
     * @param string $message
179
     * @throws QuotaExceededException
180
     */
181 6
    private function assertNoTranslateExceptionAndZeroBalance($message)
182
    {
183 6
        if (strpos($message, 'TranslateApiException') === 0
184 6
            && strpos($message, 'credentials has zero balance.')
185 6
        ) {
186 3
            throw new QuotaExceededException($message);
187
        }
188 3
    }
189
190
    /**
191
     * @param string $message
192
     * @throws ArgumentException
193
     * @throws TokenExpiredException
194
     */
195 12
    private function assertNoArgumentException($message)
196
    {
197 12
        if (strpos($message, 'Argument Exception') === 0) {
198 6
            if (strpos($message, 'The incoming token has expired.')) {
199 3
                throw new TokenExpiredException($message);
200
            }
201
202 3
            throw new ArgumentException($message);
203
        }
204 6
    }
205
206
    /**
207
     * Converts a string of text from one language to another.
208
     *
209
     * @param $text string
210
     * @param $to string|Language
211
     * @param $from string|Language
212
     * @param $contentType string
213
     * @return string A string representing the translated text.
214
     *
215
     * @throws TranslatorException
216
     */
217 18
    public function translate($text, $to, $from = null, $contentType = Translate::CONTENT_TYPE_PLAIN)
218
    {
219 18
        return $this->execute(new Translate($text, $to, $from, $contentType));
220
    }
221
222
    /**
223
     * @param $text
224
     * @return null|Language
225
     * @throws TranslatorException
226
     */
227 3
    public function detect($text)
228
    {
229 3
        return $this->execute(new Detect($text));
230
    }
231
232
    /**
233
     * @param $text
234
     * @param $language
235
     * @param string $format
236
     * @param string $options
237
     * @return mixed
238
     * @throws TranslatorException
239
     */
240 3
    public function speak($text, $language, $format = Speak::FORMAT_MP3, $options = Speak::OPTION_MAX_QUALITY)
241
    {
242 3
        return $this->execute(new Speak($text, $language, $format, $options));
243
    }
244
245
    /**
246
     * @return Language[]
247
     * @throws TranslatorException
248
     */
249 3
    public function getLanguagesForSpeak()
250
    {
251 3
        return $this->execute(new GetLanguagesForSpeak());
252
    }
253
254
    /**
255
     * @param $languageCodes
256
     * @param string $locale
257
     * @return mixed
258
     * @throws TranslatorException
259
     */
260 6
    public function getLanguageNames($languageCodes, $locale = Language::ENGLISH)
261
    {
262 6
        return $this->execute(new GetLanguageNames($locale, $languageCodes));
263
    }
264
265
    /**
266
     * @return Language[]
267
     * @throws TranslatorException
268
     */
269 3
    public function getLanguagesForTranslate()
270
    {
271 3
        return $this->execute(new GetLanguagesForTranslate());
272
    }
273
274
    /**
275
     * @param $text
276
     * @param $to
277
     * @param $from
278
     * @param null $maxTranslations
279
     * @param TranslateOptions|null $options
280
     * @return GetTranslationsResponse
281
     * @throws TranslatorException
282
     */
283 6
    public function getTranslations($text, $to, $from, $maxTranslations = 5, TranslateOptions $options = null)
284
    {
285 6
        return $this->execute(new GetTranslations($text, $to, $from, $maxTranslations, $options));
286
    }
287
288
    /**
289
     * @param $texts
290
     * @param $to
291
     * @param $from
292
     * @param int $maxTranslations
293
     * @param TranslateOptions|null $options
294
     * @return GetTranslationsResponse[]
295
     * @throws TranslatorException
296
     */
297 3
    public function getTranslationsArray($texts, $to, $from, $maxTranslations = 5, TranslateOptions $options = null)
298
    {
299 3
        return $this->execute(new GetTranslationsArray($texts, $to, $from, $maxTranslations, $options));
300
    }
301
}
302