Completed
Push — master ( 46457b...75f199 )
by Byron
02:07
created

MicrosoftTranslator::detect()   A

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