Completed
Push — master ( db2912...d1e0ef )
by Byron
02:04
created

MicrosoftTranslator::assertNoArgumentException()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 9.4285
cc 3
eloc 5
nc 3
nop 1
crap 3
1
<?php
2
namespace badams\MicrosoftTranslator;
3
4
use badams\MicrosoftTranslator\Exceptions\ArgumentException;
5
use badams\MicrosoftTranslator\Exceptions\AuthException;
6
use badams\MicrosoftTranslator\Exceptions\QuotaExceededException;
7
use badams\MicrosoftTranslator\Exceptions\TokenExpiredException;
8
use badams\MicrosoftTranslator\Exceptions\TranslatorException;
9
use badams\MicrosoftTranslator\Methods\Detect;
10
use badams\MicrosoftTranslator\Methods\Speak;
11
use badams\MicrosoftTranslator\Methods\Translate;
12
use GuzzleHttp\Exception\RequestException;
13
use GuzzleHttp\Message\ResponseInterface;
14
15
/**
16
 * Class MicrosoftTranslator
17
 * @package badams\MicrosoftTranslator
18
 */
19
class MicrosoftTranslator
20
{
21
    /**
22
     *
23
     */
24
    const AUTH_URL = 'https://datamarket.accesscontrol.windows.net/v2/OAuth2-13';
25
26
    /**
27
     *
28
     */
29
    const BASE_URL = 'http://api.microsofttranslator.com/V2/Http.svc/';
30
31
    /**
32
     * @var \GuzzleHttp\ClientInterface
33
     */
34
    private $http;
35
36
    /**
37
     * @var string
38
     */
39
    private $scope = 'http://api.microsofttranslator.com';
40
41
    /**
42
     * @var string
43
     */
44
    private $grantType = 'client_credentials';
45
46
    /**
47
     * @var string
48
     */
49
    private $clientId;
50
51
    /**
52
     * @var string
53
     */
54
    private $clientSecret;
55
56
    /**
57
     * @var string
58
     */
59
    private $accessToken;
60
61
    /**
62
     * MicrosoftTranslator constructor.
63
     */
64 30
    public function __construct(\GuzzleHttp\ClientInterface $httpClient = null)
65
    {
66 30
        if (is_null($httpClient)) {
67 3
            $httpClient = new \GuzzleHttp\Client();
68 3
        }
69
70 30
        $this->http = $httpClient;
71 30
    }
72
73
    /**
74
     * @param $id
75
     * @param $secret
76
     */
77 15
    public function setClient($id, $secret)
78
    {
79 15
        $this->clientId = $id;
80 15
        $this->clientSecret = $secret;
81 15
    }
82
83
    /**
84
     * @return mixed
85
     * @throws AuthException
86
     */
87 24
    private function getAccessToken()
88
    {
89 24
        if (!$this->accessToken) {
90 24
            $params = array_merge([
91 24
                'grant_type' => $this->grantType,
92 24
                'scope' => $this->scope,
93 24
                'client_id' => $this->clientId,
94 24
                'client_secret' => $this->clientSecret
95 24
            ]);
96
97
            try {
98 24
                $response = $this->http->post(self::AUTH_URL, ['body' => $params]);
99 21
                $result = json_decode((string)$response->getBody());
100 24
            } catch (RequestException $e) {
101 3
                $result = json_decode((string)$e->getResponse()->getBody());
102 3
                throw new AuthException($result->error_description);
103
            }
104
105 21
            $this->accessToken = $result->access_token;
106 21
        }
107
108 21
        return $this->accessToken;
109
    }
110
111 21
    private function createRequest(ApiMethodInterface $method)
112
    {
113 21
        $reflection = new \ReflectionClass($method);
114
115 21
        return $this->http->createRequest(
116 21
            $method->getRequestMethod(),
117 21
            self::BASE_URL . $reflection->getShortName(),
118 21
            array_merge([
119 21
                'exceptions' => false,
120
                'headers' => [
121 21
                    'Authorization' => 'Bearer ' . $this->getAccessToken(),
122 21
                    'Content-Type' => 'text/xml',
123 21
                ],
124
125 21
            ], $method->getRequestOptions())
126 21
        );
127
    }
128
129
    /**
130
     * @param ApiMethodInterface $method
131
     * @return mixed
132
     * @throws ArgumentException
133
     * @throws QuotaExceededException
134
     * @throws TranslatorException
135
     */
136 21
    private function execute(ApiMethodInterface $method)
137
    {
138 21
        $response = $this->http->send($this->createRequest($method));
139
140 21
        if ($response->getStatusCode() != 200) {
141
            try {
142 12
                $message = strip_tags($response->getBody());
143 12
                $this->assertNoArgumentException($message);
144 6
                $this->assertNoTranslateExceptionAndZeroBalance($message);
145 12
            } catch (TokenExpiredException $e) {
146 3
                $this->accessToken = null;
147 3
                return $this->execute($method);
148
            }
149
150 21
            throw new TranslatorException($response->getBody());
151
        }
152
153 12
        return $method->processResponse($response);
154
    }
155
156
    /**
157
     * @param string $message
158
     * @throws QuotaExceededException
159
     */
160 6
    function assertNoTranslateExceptionAndZeroBalance($message)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
161
    {
162 6
        if (strpos($message, 'TranslateApiException') === 0
163 6
            && strpos($message, 'credentials has zero balance.')
164 6
        ){
165 3
            throw new QuotaExceededException($message);
166
        }
167 3
    }
168
169
    /**
170
     * @param string $message
171
     * @throws ArgumentException
172
     * @throws TokenExpiredException
173
     */
174 12
    function assertNoArgumentException($message)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
175
    {
176 12
        if (strpos($message, 'Argument Exception') === 0) {
177 6
            if (strpos($message, 'The incoming token has expired.')) {
178 3
                throw new TokenExpiredException($message);
179
            }
180
181 3
            throw new ArgumentException($message);
182
        }
183 6
    }
184
185
    /**
186
     * @param $text
187
     * @param $to
188
     * @param $from
189
     * @return null|string
190
     */
191 15
    public function translate($text, $to, $from = null)
192
    {
193 15
        return $this->execute(new Translate($text, $to, $from));
194
    }
195
196
    /**
197
     * @param $text
198
     * @return null|string
199
     * @throws TranslatorException
200
     */
201 3
    public function detect($text)
202
    {
203 3
        return $this->execute(new Detect($text));
204
    }
205
206
    /**
207
     * @param $text
208
     * @param $language
209
     * @param string $format
210
     * @param string $options
211
     * @return mixed
212
     * @throws TranslatorException
213
     */
214 3
    public function speak($text, $language, $format = Speak::FORMAT_MP3, $options = Speak::OPTION_MAX_QUALITY)
215
    {
216 3
        return $this->execute(new Speak($text, $language, $format, $options));
217
    }
218
}