Client::page()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 9
ccs 4
cts 5
cp 0.8
rs 10
cc 2
nc 2
nop 1
crap 2.032
1
<?php
2
3
namespace sokolnikov911\YandexXml;
4
5
use sokolnikov911\YandexXml\Exceptions\YandexException;
6
use sokolnikov911\YandexXml\Exceptions\YandexInvalidArgumentException;
7
use GuzzleHttp\Client as HttpClient;
8
use GuzzleHttp\Exception\ClientException;
9
use GuzzleHttp\Exception\GuzzleException;
10
11
class Client
12
{
13
    private $user;
14
    private $key;
15
    private $selectedLanguage;
16
17
    private $lr;
18
    private $l10n;
19
    private $sortByType;
20
    private $sortByDirection;
21
    private $filter;
22
    private $maxPassages;
23
    private $groupByMode;
24
    private $groupByGroupsOnPage;
25
    private $groupByDocsInGroup;
26
    private $page;
27
    private $showMeCaptcha;
28
    private $action;
29
    private $query;
30
31
    private $url = 'https://yandex.{lang}/search/xml';
32
33
    const AVAILABLE_REGIONS = [
34
        '225', '187', '149', '159', '20', '1092', '37', '30', '197', '47', '4', '65', '77', '66', '191', '10', '24',
35
        '48', '75', '49', '33', '50', '192', '25', '38', '39', '21', '11', '193', '51', '1106', '2', '54', '42', '5',
36
        '12', '63', '239', '41', '36', '43', '973', '22', '13', '64', '14', '7', '67', '35', '15', '62', '195', '53',
37
        '172', '8', '76', '9', '45', '28', '56', '1', '1104', '213', '16', '23'
38
    ];
39
40
    const DOMAIN_RU = 'ru';
41
    const DOMAIN_COM_TR = 'com.tr';
42
    const DOMAIN_COM = 'com';
43
44
    const ACTION_LIMITS_INFO = 'limits-info';
45
46
    const L10N_RUSSIAN = 'ru';
47
    const L10N_UKRAINIAN = 'uk';
48
    const L10N_BELARUSIAN = 'be';
49
    const L10N_KAZAKH = 'kk';
50
    const L10N_TURKISH = 'tr';
51
    const L10N_ENGLISH = 'en';
52
53
    const SORT_BY_RLV = 'rlv';
54
    const SORT_BY_TM = 'tm';
55
56
    const SORTING_DIRECTION_DESC = 'descending';
57
    const SORTING_DIRECTION_ASC = 'ascending';
58
59
    const FILTER_STRICT = 'strict';
60
    const FILTER_MODERATE = 'moderate';
61
    const FILTER_NONE = 'none';
62
63
    const GROUP_MODE_FLAT = 'flat';
64
    const GROUP_MODE_DEEP = 'deep';
65
66
    /**
67
     * @param string $user API user
68
     * @param string $key API key
69
     * @param string|null $domainLanguage (optional) Domain language
70
     * @param string|null $endpointUrl
71
     * @see https://yandex.ru/dev/xml/
72
     */
73 40
    public function __construct(string $user, string $key, ?string $domainLanguage = null,
74
                                ?string $endpointUrl = null)
75
    {
76 40
        $this->user = $user;
77 40
        $this->key = $key;
78 40
        $this->selectedLanguage = $domainLanguage;
79
80 40
        if ($domainLanguage === null) {
81 40
            $this->selectedLanguage = self::DOMAIN_RU;
82
        }
83
84 40
        if ($endpointUrl !== null) {
85 2
            $this->url = $endpointUrl;
86
        }
87
    }
88
89
    /**
90
     * Set a search region id. Region list you can find here: https://yandex.ru/dev/xml/doc/dg/reference/regions.html/
91
     *
92
     * @param integer $lr region id
93
     * @return Client $client
94
     * @throws YandexInvalidArgumentException
95
     * @see https://yandex.ru/dev/xml/doc/dg/reference/regions.html/
96
     */
97 2
    public function lr(int $lr): Client
98
    {
99 2
        if (!in_array($lr, self::AVAILABLE_REGIONS)) {
100
            throw new YandexInvalidArgumentException();
101
        }
102
103 2
        $this->lr = $lr;
104
105 2
        return $this;
106
    }
107
108
    /**
109
     * Set a response language
110
     *
111
     * @param string $l10n region id
112
     * @return Client $client
113
     * @throws YandexInvalidArgumentException
114
     */
115 2
    public function l10n(string $l10n): Client
116
    {
117 2
        if (!in_array($l10n, [self::L10N_TURKISH, self::L10N_ENGLISH, self::L10N_BELARUSIAN, self::L10N_KAZAKH,
118
            self::L10N_RUSSIAN, self::L10N_UKRAINIAN])) {
119
            throw new YandexInvalidArgumentException();
120
        }
121
122 2
        if (($l10n == self::L10N_TURKISH) && ($this->selectedLanguage != self::DOMAIN_COM_TR)) {
123
            throw new YandexInvalidArgumentException();
124
        }
125
126 2
        if (($l10n == self::L10N_ENGLISH) && ($this->selectedLanguage != self::DOMAIN_COM)) {
127
            throw new YandexInvalidArgumentException();
128
        }
129
130 2
        $this->l10n = $l10n;
131
132 2
        return $this;
133
    }
134
135
    /**
136
     * Set a search region id. Region list you can find here: https://yandex.ru/dev/xml/doc/dg/reference/regions.html/
137
     *
138
     * @param string $type sorting type
139
     * @param string|null $direction (optional) sorting direction
140
     * @return Client $client
141
     * @throws YandexInvalidArgumentException
142
     */
143 6
    public function sortBy(string $type, ?string $direction = null): Client
144
    {
145 6
        if (!in_array($type, [self::SORT_BY_TM, self::SORT_BY_RLV])) {
146
            throw new YandexInvalidArgumentException();
147
        }
148
149 6
        if (($type == self::SORT_BY_TM) && ($direction !== null)) {
150 4
            if (!in_array($direction, [self::SORTING_DIRECTION_ASC, self::SORTING_DIRECTION_DESC])) {
151
                throw new YandexInvalidArgumentException();
152
            }
153
154 4
            $this->sortByDirection = $direction;
155
        }
156
157 6
        $this->sortByType = $type;
158
159 6
        return $this;
160
    }
161
162
    /**
163
     * Set a filtering rules
164
     *
165
     * @param string $type filtering type
166
     * @return Client $client
167
     * @throws YandexInvalidArgumentException
168
     */
169 2
    public function filter(string $type): Client
170
    {
171 2
        if (!in_array($type, [self::FILTER_MODERATE, self::FILTER_NONE, self::FILTER_STRICT])) {
172
            throw new YandexInvalidArgumentException();
173
        }
174
175 2
        $this->filter = $type;
176
177 2
        return $this;
178
    }
179
180
    /**
181
     * Set a maximum passages number
182
     *
183
     * @param integer $number maximum passages number
184
     * @return Client $client
185
     * @throws YandexInvalidArgumentException
186
     */
187 2
    public function maxPassages(int $number): Client
188
    {
189 2
        if (($number < 1) || ($number > 5)) {
190
            throw new YandexInvalidArgumentException();
191
        }
192
193 2
        $this->maxPassages = $number;
194
195 2
        return $this;
196
    }
197
198
    /**
199
     * Set a grouping rules
200
     *
201
     * @param string $mode grouping method
202
     * @param integer|null $groupsOnPage (optional) groups on page number
203
     * @param integer|null $docsInGroup (optional) documents in group number
204
     * @return Client $client
205
     * @throws YandexInvalidArgumentException
206
     */
207 10
    public function groupBy(string $mode,
208
                            ?int $groupsOnPage = null,
209
                            ?int $docsInGroup = null): Client
210
    {
211 10
        if (!in_array($mode, [self::GROUP_MODE_DEEP, self::GROUP_MODE_FLAT])) {
212
            throw new YandexInvalidArgumentException();
213
        }
214
215 10
        if (($groupsOnPage !== null) && (($groupsOnPage < 1) || ($groupsOnPage > 100))) {
216
            throw new YandexInvalidArgumentException();
217
        }
218
219 10
        if (($docsInGroup !== null) && (($docsInGroup < 1) || ($docsInGroup > 3))) {
220
            throw new YandexInvalidArgumentException();
221
        }
222
223 10
        $this->groupByMode = $mode;
224
225 10
        if ($groupsOnPage !== null) {
226 2
            $this->groupByGroupsOnPage = $groupsOnPage;
227
        }
228
229 10
        if ($docsInGroup !== null) {
230 2
            $this->groupByDocsInGroup = $docsInGroup;
231
        }
232
233 10
        return $this;
234
    }
235
236
    /**
237
     * Set a page number
238
     *
239
     * @param integer $number page number. Starts from "0"
240
     * @return Client $client
241
     * @throws YandexInvalidArgumentException
242
     */
243 2
    public function page(int $number): Client
244
    {
245 2
        if ($number < 0) {
246
            throw new YandexInvalidArgumentException();
247
        }
248
249 2
        $this->page = $number;
250
251 2
        return $this;
252
    }
253
254
    /**
255
     * Enable Captcha on result page
256
     *
257
     * @return Client $client
258
     */
259 2
    public function showMeCaptcha(): Client
260
    {
261 2
        $this->showMeCaptcha = 'yes';
262
263 2
        return $this;
264
    }
265
266
    /**
267
     * Set query string
268
     *
269
     * @param string $query query string
270
     * @return Client $client
271
     */
272 16
    public function query(string $query): Client
273
    {
274 16
        $this->query = $query;
275
276 16
        return $this;
277
    }
278
279
    /**
280
     * Set action value (at this time uses only for getting information about day or hour limits)
281
     *
282
     * @return Client $client
283
     */
284 4
    public function action(): Client
285
    {
286 4
        $this->action = self::ACTION_LIMITS_INFO;
287
288 4
        return $this;
289
    }
290
291
    /**
292
     * Retrieving search results
293
     *
294
     * @return string Response body
295
     * @throws YandexException|ClientException|GuzzleException
296
     */
297
    public function get(): string
298
    {
299
        $data = $this->getData();
300
301
        return $data ? $data : '';
302
    }
303
304
    /**
305
     * Sends a request
306
     *
307
     * @return string Response body
308
     * @throws YandexException|ClientException|GuzzleException
309
     */
310
    protected function getData(): string
311
    {
312
        $url = $this->getEndpointUrlWithParams();
313
314
        $client = new HttpClient();
315
316
        try {
317
            $response = $client->get($url);
318
        } catch (ClientException $e) {
319
            $response = $e->getResponse();
320
            $responseData = $response->getBody()->getContents();
321
322
            $xml = simplexml_load_string($responseData);
323
            $responseData = json_encode($xml, JSON_UNESCAPED_UNICODE);
324
325
            $dataArray = json_decode($responseData, true);
326
327
            if ($dataArray['response'] && $dataArray['response']['error']) {
328
                throw new YandexException($dataArray['error']['text'], $dataArray['response']['error']);
329
            } else throw $e;
330
        }
331
332
        return $response->getBody();
333
    }
334
335 2
    private function generateSortByAttribute(): string
336
    {
337 2
        $string = $this->sortByType;
338
339 2
        if ($this->sortByDirection) {
340 2
            $string .= '.order=' . $this->sortByDirection;
341
        }
342
343 2
        return $string;
344
    }
345
346 8
    private function generateGroupByAttribute(): string
347
    {
348 8
        $string = $this->groupByMode;
349
350 8
        if ($this->groupByMode == self::GROUP_MODE_DEEP) {
351 2
            $string .= '.attr=d';
352
        }
353
354 8
        if ($this->groupByGroupsOnPage) {
355 2
            $string .= '.groups-on-page=' . $this->groupByGroupsOnPage;
356
        }
357
358 8
        if ($this->groupByDocsInGroup) {
359 2
            $string .= '.docs-in-group=' . $this->groupByDocsInGroup;
360
        }
361
362 8
        return $string;
363
    }
364
365
    /**
366
     * Generates end-point URL with parameters
367
     *
368
     * @return string Full end-point URL
369
     * @throws YandexException
370
     */
371 16
    public function getEndpointUrlWithParams(): string
372
    {
373 16
        $url = $this->getEndpointUrl();
374
375 16
        if ($this->action) {
376 2
            $params = $this->getActionParams();
377
        } else {
378 14
            if (!$this->query) {
379
                throw new YandexException();
380
            }
381
382 14
            $params = $this->getQueryParams();
383
        }
384
385 16
        $params['user'] = $this->user;
386 16
        $params['key'] = $this->key;
387
388 16
        return $url . '?' . http_build_query($params);
389
    }
390
391
    /**
392
     * Generates action parameters array
393
     *
394
     * @return array Action parameters array
395
     */
396 2
    private function getActionParams(): array
397
    {
398
        return [
399 2
            'action' => $this->action
400
        ];
401
    }
402
403
    /**
404
     * Generates query parameters array
405
     *
406
     * @return array Query parameters array
407
     */
408 14
    private function getQueryParams(): array
409
    {
410
        $params = [
411 14
            'query' => $this->query
412
        ];
413
414 14
        if ($this->lr) $params['lr'] = $this->lr;
415 14
        if ($this->l10n) $params['l10n'] = $this->l10n;
416 14
        if ($this->page) $params['page'] = $this->page;
417 14
        if ($this->showMeCaptcha) $params['showmecaptcha'] = $this->showMeCaptcha;
418 14
        if ($this->maxPassages) $params['maxpassages'] = $this->maxPassages;
419 14
        if ($this->filter) $params['filter'] = $this->filter;
420 14
        if ($this->sortByType) $params['sortby'] = $this->generateSortByAttribute();
421 14
        if ($this->groupByMode) $params['groupby'] = $this->generateGroupByAttribute();
422
423 14
        return $params;
424
    }
425
426
    /**
427
     * Generates end-point URL
428
     *
429
     * @return string Full end-point URL
430
     */
431 18
    public function getEndpointUrl(): string
432
    {
433 18
        return str_replace('{lang}', $this->selectedLanguage, $this->url);
434
    }
435
}