Completed
Push — master ( dd3387...bebc05 )
by Byron
02:09
created

MicrosoftTranslator::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.1481

Importance

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