Completed
Push — master ( 15868f...f539cf )
by Byron
03:26
created

MicrosoftTranslator::setClient()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
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\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 39
    public function __construct(\GuzzleHttp\ClientInterface $httpClient = null)
77
    {
78 39
        if (is_null($httpClient)) {
79 3
            $httpClient = new \GuzzleHttp\Client();
80 3
        }
81
82 39
        $this->http = $httpClient;
83 39
    }
84
85
    /**
86
     * @param $id
87
     * @param $secret
88
     */
89 24
    public function setClient($id, $secret)
90
    {
91 24
        $this->clientId = $id;
92 24
        $this->clientSecret = $secret;
93 24
    }
94
95
    /**
96
     * @return mixed
97
     * @throws AuthException
98
     */
99 33
    private function getAccessToken()
100
    {
101 33
        if (!$this->accessToken) {
102 33
            $params = array_merge([
103 33
                'grant_type' => $this->grantType,
104 33
                'scope' => $this->scope,
105 33
                'client_id' => $this->clientId,
106 33
                'client_secret' => $this->clientSecret
107 33
            ]);
108
109
            try {
110 33
                $response = $this->http->post(self::AUTH_URL, ['body' => $params]);
111 30
                $result = json_decode((string)$response->getBody());
112 33
            } catch (RequestException $e) {
113 3
                $result = json_decode((string)$e->getResponse()->getBody());
114 3
                throw new AuthException($result->error_description);
115
            }
116
117 30
            $this->accessToken = $result->access_token;
118 30
        }
119
120 30
        return $this->accessToken;
121
    }
122
123
    /**
124
     * @param ApiMethodInterface $method
125
     * @return \GuzzleHttp\Message\Request|\GuzzleHttp\Message\RequestInterface
126
     * @throws AuthException
127
     */
128 30
    private function createRequest(ApiMethodInterface $method)
129
    {
130 30
        $reflection = new \ReflectionClass($method);
131
132 30
        return $this->http->createRequest(
133 30
            $method->getRequestMethod(),
134 30
            self::BASE_URL . $reflection->getShortName(),
135 30
            array_merge([
136 30
                'exceptions' => false,
137
                'headers' => [
138 30
                    'Authorization' => 'Bearer ' . $this->getAccessToken(),
139 30
                    'Content-Type' => 'text/xml',
140 30
                ],
141
142 30
            ], $method->getRequestOptions())
143 30
        );
144
    }
145
146
    /**
147
     * @param ApiMethodInterface $method
148
     * @return mixed
149
     * @throws ArgumentException
150
     * @throws QuotaExceededException
151
     * @throws TranslatorException
152
     */
153 30
    private function execute(ApiMethodInterface $method)
154
    {
155 30
        $response = $this->http->send($this->createRequest($method));
156
157 30
        if ($response->getStatusCode() != 200) {
158
            try {
159 12
                $message = strip_tags($response->getBody());
160 12
                $this->assertNoArgumentException($message);
161 6
                $this->assertNoTranslateExceptionAndZeroBalance($message);
162 12
            } catch (TokenExpiredException $e) {
163 3
                $this->accessToken = null;
164 3
                return $this->execute($method);
165
            }
166
167 3
            throw new TranslatorException($response->getBody());
168
        }
169
170 21
        return $method->processResponse($response);
171
    }
172
173
    /**
174
     * @param string $message
175
     * @throws QuotaExceededException
176
     */
177 6
    private function assertNoTranslateExceptionAndZeroBalance($message)
178
    {
179 6
        if (strpos($message, 'TranslateApiException') === 0
180 6
            && strpos($message, 'credentials has zero balance.')
181 6
        ) {
182 3
            throw new QuotaExceededException($message);
183
        }
184 3
    }
185
186
    /**
187
     * @param string $message
188
     * @throws ArgumentException
189
     * @throws TokenExpiredException
190
     */
191 12
    private function assertNoArgumentException($message)
192
    {
193 12
        if (strpos($message, 'Argument Exception') === 0) {
194 6
            if (strpos($message, 'The incoming token has expired.')) {
195 3
                throw new TokenExpiredException($message);
196
            }
197
198 3
            throw new ArgumentException($message);
199
        }
200 6
    }
201
202
    /**
203
     * @param $text
204
     * @param $to
205
     * @param $from
206
     * @return null|string
207
     */
208 15
    public function translate($text, $to, $from = null)
209
    {
210 15
        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 3
    public function speak($text, $language, $format = Speak::FORMAT_MP3, $options = Speak::OPTION_MAX_QUALITY)
232
    {
233 3
        return $this->execute(new Speak($text, $language, $format, $options));
234
    }
235
236
    /**
237
     * @return Language[]
238
     * @throws TranslatorException
239
     */
240 3
    public function getLanguagesForSpeak()
241
    {
242 3
        return $this->execute(new GetLanguagesForSpeak());
243
    }
244
245
    /**
246
     * @param $languageCodes
247
     * @param string $locale
248
     * @return mixed
249
     * @throws TranslatorException
250
     */
251 6
    public function getLanguageNames($languageCodes, $locale = Language::ENGLISH)
252
    {
253 6
        return $this->execute(new GetLanguageNames($locale, $languageCodes));
254
    }
255
}