YandexDictionaryApi::processPosFrom()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace GinoPane\PHPolyglot\API\Implementation\Dictionary\Yandex;
4
5
use GinoPane\NanoRest\Request\RequestContext;
6
use GinoPane\NanoRest\Response\ResponseContextAbstract;
7
use GinoPane\PHPolyglot\Supplemental\Language\Language;
8
use GinoPane\PHPolyglot\Exception\InvalidResponseContent;
9
use GinoPane\NanoRest\Exceptions\RequestContextException;
10
use GinoPane\PHPolyglot\Exception\BadResponseContextException;
11
use GinoPane\PHPolyglot\API\Supplemental\Yandex\YandexApiTrait;
12
use GinoPane\PHPolyglot\API\Response\Dictionary\DictionaryResponse;
13
use GinoPane\PHPolyglot\API\Response\Dictionary\Entry\DictionaryEntry;
14
use GinoPane\PHPolyglot\API\Response\Dictionary\Entry\POS\DictionaryEntryPos;
15
use GinoPane\PHPolyglot\API\Implementation\Dictionary\DictionaryApiAbstract;
16
17
/**
18
 * Class YandexDictionaryApi
19
 *
20
 * Yandex Dictionary API implementation
21
 *
22
 * API version 1
23
 *
24
 * @link   https://tech.yandex.com/dictionary/doc/dg/concepts/api-overview-docpage/
25
 * @link   https://tech.yandex.com/keys/?service=dict
26
 *
27
 * @author Sergey <Gino Pane> Karavay
28
 */
29
class YandexDictionaryApi extends DictionaryApiAbstract
30
{
31
    /**
32
     * Family search filter (child-safe)
33
     */
34
    const LOOKUP_FAMILY_FLAG = 0x1;
35
36
    /**
37
     * Search by word form
38
     */
39
    const LOOKUP_MORPHO_FLAG = 0x4;
40
41
    /**
42
     * Enable a filter that requires matching parts of speech for the search word and translation
43
     */
44
    const LOOKUP_POS_FILTER_FLAG = 0x8;
45
46
    /**
47
     * URL path for lookup action
48
     */
49
    protected const LOOKUP_API_PATH = 'lookup';
50
51
    /**
52
     * Main API endpoint
53
     *
54
     * @var string
55
     */
56
    protected $apiEndpoint = 'https://dictionary.yandex.net/api/v1/dicservice.json';
57
58
    /**
59
     * Mapping of properties to environment variables which must supply these properties
60
     *
61
     * @var array
62
     */
63
    protected $envProperties = [
64
        'apiKey' => 'YANDEX_DICTIONARY_API_KEY'
65
    ];
66
67
    use YandexApiTrait;
68
69
    /**
70
     * Create request context for get-text-alternatives request
71
     *
72
     * @param string   $text
73
     * @param Language $language
74
     *
75
     * @throws RequestContextException
76
     *
77
     * @return RequestContext
78
     */
79
    protected function createGetTextAlternativesContext(
80
        string $text,
81
        Language $language
82
    ): RequestContext {
83
        $requestContext = $this->getLookupRequest($text, $language, $language);
84
85
        return $this->fillGeneralRequestSettings($requestContext);
86
    }
87
88
    /**
89
     * Process response of get-text-alternatives request and prepare valid response
90
     *
91
     * @param ResponseContextAbstract $context
92
     *
93
     * @return DictionaryResponse
94
     */
95
    protected function prepareGetTextAlternativesResponse(ResponseContextAbstract $context): DictionaryResponse
96
    {
97
        return $this->processLookupResponse($context);
98
    }
99
100
    /**
101
     * Create request context for get-translate-alternatives request
102
     *
103
     * @param string   $text
104
     * @param Language $languageTo
105
     * @param Language $languageFrom
106
     *
107
     * @throws RequestContextException
108
     *
109
     * @return RequestContext
110
     */
111
    protected function createGetTranslateAlternativesContext(
112
        string $text,
113
        Language $languageTo,
114
        Language $languageFrom
115
    ): RequestContext {
116
        $requestContext = $this->getLookupRequest($text, $languageTo, $languageFrom);
117
118
        return $this->fillGeneralRequestSettings($requestContext);
119
    }
120
121
    /**
122
     * Process response of get-translate-alternatives request and prepare valid response
123
     *
124
     * @param ResponseContextAbstract $context
125
     *
126
     * @return DictionaryResponse
127
     */
128
    protected function prepareGetTranslateAlternativesResponse(ResponseContextAbstract $context): DictionaryResponse
129
    {
130
        return $this->processLookupResponse($context);
131
    }
132
133
    /**
134
     * Filters ResponseContext from common HTTP errors
135
     *
136
     * @param ResponseContextAbstract $responseContext
137
     *
138
     * @throws InvalidResponseContent
139
     * @throws BadResponseContextException
140
     */
141
    protected function processApiResponseContextErrors(ResponseContextAbstract $responseContext): void
142
    {
143
        $responseArray = $responseContext->getArray();
144
145
        $this->filterYandexSpecificErrors($responseArray);
146
147
        parent::processApiResponseContextErrors($responseContext);
148
149
        if (!isset($responseArray['def'])) {
150
            throw new InvalidResponseContent(sprintf('There is no required field "%s" in response', 'def'));
151
        }
152
    }
153
154
    /**
155
     * @param string   $text
156
     * @param Language $languageTo
157
     * @param Language $languageFrom
158
     *
159
     * @return RequestContext
160
     * @throws RequestContextException
161
     */
162
    private function getLookupRequest(string $text, Language $languageTo, Language $languageFrom): RequestContext
163
    {
164
        $requestContext = (new RequestContext(sprintf("%s/%s", $this->apiEndpoint, self::LOOKUP_API_PATH)))
165
            ->setRequestParameters(
166
                [
167
                    'lang' => $this->getLanguageString($languageTo, $languageFrom),
168
                    'flags' => self::LOOKUP_MORPHO_FLAG,
169
                    'ui' => Language::CODE_ENGLISH
170
                ] + $this->getAuthData()
171
            )
172
            ->setData(['text' => $text])
173
            ->setMethod(RequestContext::METHOD_POST);
174
175
        return $requestContext;
176
    }
177
178
    /**
179
     * @param ResponseContextAbstract $context
180
     *
181
     * @return DictionaryResponse
182
     */
183
    private function processLookupResponse(ResponseContextAbstract $context): DictionaryResponse
184
    {
185
        $responseArray = $context->getArray()['def'];
186
187
        $response = new DictionaryResponse();
188
189
        foreach ($responseArray as $sourceTextGroup) {
190
            if (empty($sourceTextGroup['text'])) {
191
                continue;
192
            }
193
194
            if (empty($sourceTextGroup['tr']) || !is_array($sourceTextGroup['tr'])) {
195
                continue;
196
            }
197
198
            $this->processTextGroup($sourceTextGroup, $response);
199
        }
200
201
        return $response;
202
    }
203
204
    /**
205
     * @param $sourceTextGroup
206
     * @param $response
207
     *
208
     * @return mixed
209
     */
210
    private function processTextGroup(array $sourceTextGroup, DictionaryResponse $response)
211
    {
212
        foreach ($sourceTextGroup['tr'] as $targetTextGroup) {
213
            if (empty($targetTextGroup['text'])) {
214
                continue;
215
            }
216
217
            $entry = new DictionaryEntry();
218
219
            $entry->setTextFrom($sourceTextGroup['text']);
220
            $entry->setTextTo($targetTextGroup['text']);
221
222
            $this->processTranscription($sourceTextGroup, $entry);
223
            $this->processPosFrom($sourceTextGroup, $entry);
224
            $this->processPosTo($targetTextGroup, $entry);
225
            $this->processSynonyms($targetTextGroup, $entry);
226
            $this->processMeanings($targetTextGroup, $entry);
227
            $this->processExamples($targetTextGroup, $entry);
228
229
            $response->addEntry($entry);
230
        }
231
232
        return $sourceTextGroup;
233
    }
234
235
    /**
236
     * @param array           $sourceTextGroup
237
     * @param DictionaryEntry $entry
238
     *
239
     * @return void
240
     */
241
    private function processTranscription(array $sourceTextGroup, DictionaryEntry $entry): void
242
    {
243
        if (!empty($sourceTextGroup['ts'])) {
244
            $entry->setTranscription($sourceTextGroup['ts']);
245
        }
246
    }
247
248
    /**
249
     * @param array           $sourceTextGroup
250
     * @param DictionaryEntry $entry
251
     *
252
     * @return void
253
     */
254
    private function processPosFrom(array $sourceTextGroup, DictionaryEntry $entry): void
255
    {
256
        if (!empty($sourceTextGroup['pos'])) {
257
            $entry->setPosFrom(new DictionaryEntryPos($sourceTextGroup['pos']));
258
        }
259
    }
260
261
    /**
262
     * @param array           $targetTextGroup
263
     * @param DictionaryEntry $entry
264
     *
265
     * @return void
266
     */
267
    private function processPosTo(array $targetTextGroup, DictionaryEntry $entry): void
268
    {
269
        if (!empty($targetTextGroup['pos'])) {
270
            $entry->setPosTo(new DictionaryEntryPos($targetTextGroup['pos']));
271
        }
272
    }
273
274
    /**
275
     * @param array           $targetTextGroup
276
     * @param DictionaryEntry $entry
277
     *
278
     * @return void
279
     */
280
    private function processSynonyms(array $targetTextGroup, DictionaryEntry $entry): void
281
    {
282
        if (!empty($targetTextGroup['syn']) && is_array($targetTextGroup['syn'])) {
283
            $synonyms = [];
284
285
            foreach ($targetTextGroup['syn'] as $synonym) {
286
                if (empty($synonym['text'])) {
287
                    continue;
288
                }
289
290
                $synonyms[] = $synonym['text'];
291
            }
292
293
            $entry->setSynonyms($synonyms);
294
        }
295
    }
296
297
    /**
298
     * @param array           $targetTextGroup
299
     * @param DictionaryEntry $entry
300
     *
301
     * @return void
302
     */
303
    private function processMeanings(array $targetTextGroup, DictionaryEntry $entry): void
304
    {
305
        if (!empty($targetTextGroup['mean']) && is_array($targetTextGroup['mean'])) {
306
            $meanings = [];
307
308
            foreach ($targetTextGroup['mean'] as $meaning) {
309
                if (empty($meaning['text'])) {
310
                    continue;
311
                }
312
313
                $meanings[] = $meaning['text'];
314
            }
315
316
            $entry->setMeanings($meanings);
317
        }
318
    }
319
320
    /**
321
     * @param array           $targetTextGroup
322
     * @param DictionaryEntry $entry
323
     *
324
     * @return void
325
     */
326
    private function processExamples(array $targetTextGroup, DictionaryEntry $entry): void
327
    {
328
        if (!empty($targetTextGroup['ex']) && is_array($targetTextGroup['ex'])) {
329
            $examples = [];
330
331
            foreach ($targetTextGroup['ex'] as $example) {
332
                if (empty($example['text']) || empty($example['tr'][0]['text'])) {
333
                    continue;
334
                }
335
336
                $examples[$example['text']] = $example['tr'][0]['text'];
337
            }
338
339
            $entry->setExamples($examples);
340
        }
341
    }
342
}
343