Passed
Pull Request — master (#31)
by
unknown
01:51
created

Client::setProxy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 1
b 0
f 1
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
namespace BabyMarkt\DeepL;
4
5
/**
6
 * Class Client implements a DeepL http Client based on PHP-CURL
7
 */
8
final class Client implements ClientInterface
9
{
10
    const API_URL_SCHEMA = 'https';
11
12
    /**
13
     * API BASE URL
14
     * https://api.deepl.com/v2/[resource]?auth_key=[yourAuthKey]
15
     */
16
    const API_URL_BASE = '%s://%s/v%s/%s?auth_key=%s';
17
18
    /**
19
     * API BASE URL without authentication query parameter
20
     * https://api.deepl.com/v2/[resource]
21
     */
22
    const API_URL_BASE_NO_AUTH = '%s://%s/v%s/%s';
23
24
    /**
25
     * DeepL API Version (v2 is default since 2018)
26
     *
27
     * @var integer
28
     */
29
    protected $apiVersion;
30
31
    /**
32
     * DeepL API Auth Key (DeepL Pro access required)
33
     *
34
     * @var string
35
     */
36
    protected $authKey;
37
38
    /**
39
     * cURL resource
40
     *
41
     * @var resource
42
     */
43
    protected $curl;
44
45
    /**
46
     * Hostname of the API (in most cases api.deepl.com)
47
     *
48
     * @var string
49
     */
50
    protected $host;
51
52
    /**
53
     * Maximum number of seconds the query should take
54
     *
55
     * @var int|null
56
     */
57
    protected $timeout = null;
58
59
    /**
60
     * URL of the proxy used to connect to DeepL (if needed)
61
     *
62
     * @var string|null
63
     */
64
    protected $proxy = null;
65
66
    /**
67
     * Credentials for the proxy used to connect to DeepL (username:password)
68
     *
69
     * @var string|null
70
     */
71
    protected $proxyCredentials = null;
72
73
    /**
74
     * DeepL constructor
75
     *
76
     * @param string  $authKey
77
     * @param integer $apiVersion
78
     * @param string  $host
79
     */
80
    public function __construct($authKey, $apiVersion = 2, $host = 'api.deepl.com')
81
    {
82
        $this->authKey    = $authKey;
83
        $this->apiVersion = $apiVersion;
84
        $this->host       = $host;
85
        $this->curl       = curl_init();
0 ignored issues
show
Documentation Bug introduced by
It seems like curl_init() can also be of type CurlHandle. However, the property $curl is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
86
87
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
88
    }
89
90
    /**
91
     * DeepL destructor
92
     */
93
    public function __destruct()
94
    {
95
        if ($this->curl && is_resource($this->curl)) {
96
            curl_close($this->curl);
97
        }
98
    }
99
100
    /**
101
     * Make a request to the given URL
102
     *
103
     * @param string $url
104
     * @param string $body
105
     * @param string $method
106
     *
107
     * @return array
108
     *
109
     * @throws DeepLException
110
     */
111
    public function request($url, $body = '', $method = 'POST')
112
    {
113
        switch ($method) {
114
            case 'DELETE':
115
                curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
116
                break;
117
            case 'POST':
118
                curl_setopt($this->curl, CURLOPT_POST, true);
119
                curl_setopt($this->curl, CURLOPT_POSTFIELDS, $body);
120
                break;
121
            case 'GET':
122
            default:
123
                break;
124
        }
125
126
        curl_setopt($this->curl, CURLOPT_URL, $url);
127
128
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
129
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, array("Authorization: DeepL-Auth-Key $this->authKey"));
130
131
        if ($this->proxy !== null) {
132
            curl_setopt($this->curl, CURLOPT_PROXY, $this->proxy);
133
        }
134
135
        if ($this->proxyCredentials !== null) {
136
            curl_setopt($this->curl, CURLOPT_PROXYAUTH, $this->proxyCredentials);
137
        }
138
139
        if ($this->timeout !== null) {
140
            curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout);
141
        }
142
143
        $response = curl_exec($this->curl);
144
145
        if (curl_errno($this->curl)) {
146
            throw new DeepLException('There was a cURL Request Error : ' . curl_error($this->curl));
147
        }
148
        $httpCode = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
149
150
        return $this->handleResponse($response, $httpCode);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->handleResp...e($response, $httpCode) also could return the type string|true which is incompatible with the documented return type array.
Loading history...
151
    }
152
153
    /**
154
     * Set a proxy to use for querying the DeepL API if needed
155
     *
156
     * @param string $proxy Proxy URL (e.g 'http://proxy-domain.com:3128')
157
     */
158
    public function setProxy($proxy)
159
    {
160
        $this->proxy = $proxy;
161
    }
162
163
    /**
164
     * Set the proxy credentials
165
     *
166
     * @param string $proxyCredentials proxy credentials (using 'username:password' format)
167
     */
168
    public function setProxyCredentials($proxyCredentials)
169
    {
170
        $this->proxyCredentials = $proxyCredentials;
171
    }
172
173
    /**
174
     * Set a timeout for queries to the DeepL API
175
     *
176
     * @param int $timeout Timeout in seconds
177
     */
178
    public function setTimeout($timeout)
179
    {
180
        $this->timeout = $timeout;
181
    }
182
183
    /**
184
     * Creates the Base-Url which all the API-resources have in common.
185
     *
186
     * @param string $resource
187
     * @param bool   $withAuth
188
     *
189
     * @return string
190
     */
191
    public function buildBaseUrl(string $resource = 'translate'): string
192
    {
193
//        if (!empty($this->authKey)) {
194
//            return sprintf(
195
//                self::API_URL_BASE,
196
//                self::API_URL_SCHEMA,
197
//                $this->host,
198
//                $this->apiVersion,
199
//                $resource,
200
//                $this->authKey
201
//            );
202
//        }
203
204
        return sprintf(
205
            self::API_URL_BASE_NO_AUTH,
206
            self::API_URL_SCHEMA,
207
            $this->host,
208
            $this->apiVersion,
209
            $resource
210
        );
211
    }
212
213
    /**
214
     * @param array $paramsArray
215
     *
216
     * @return string
217
     */
218
    public function buildQuery($paramsArray)
219
    {
220
        if (isset($paramsArray['text']) && true === is_array($paramsArray['text'])) {
221
            $text = $paramsArray['text'];
222
            unset($paramsArray['text']);
223
            $textString = '';
224
            foreach ($text as $textElement) {
225
                $textString .= '&text='.rawurlencode($textElement);
226
            }
227
        }
228
229
        foreach ($paramsArray as $key => $value) {
230
            if (true === is_array($value)) {
231
                $paramsArray[$key] = implode(',', $value);
232
            }
233
        }
234
235
        $body = http_build_query($paramsArray, null, '&');
0 ignored issues
show
Bug introduced by
null of type null is incompatible with the type string expected by parameter $numeric_prefix of http_build_query(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

235
        $body = http_build_query($paramsArray, /** @scrutinizer ignore-type */ null, '&');
Loading history...
236
237
        if (isset($textString)) {
238
            $body = $textString.'&'.$body;
239
        }
240
241
        return $body;
242
    }
243
244
    /**
245
     * Handles the different kind of response returned from API, array, string or null
246
     *
247
     * @param $response
248
     * @param $httpCode
249
     * @return array|mixed|null
250
     * @throws DeepLException
251
     */
252
    private function handleResponse($response, $httpCode)
253
    {
254
        $responseArray = json_decode($response, true);
255
        if (($httpCode === 200 || $httpCode === 204) && is_null($responseArray)) {
256
            return empty($response) ? null : $response;
257
        }
258
259
        if ($httpCode !== 200 && is_array($responseArray) && array_key_exists('message', $responseArray)) {
260
            throw new DeepLException($responseArray['message'], $httpCode);
261
        }
262
263
        if (!is_array($responseArray)) {
264
            throw new DeepLException('The Response seems to not be valid JSON.', $httpCode);
265
        }
266
267
        return $responseArray;
268
    }
269
}
270