Completed
Push — master ( 2fb7dc...24e01c )
by Владислав
02:16
created

DeCaptchaWiki   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 588
Duplicated Lines 6.46 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 53
lcom 1
cbo 1
dl 38
loc 588
rs 7.4757
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A setLang() 0 4 1
B __construct() 0 279 1
A setText() 0 7 2
C getText() 0 28 7
A viewInstall() 0 16 1
F viewExamples() 38 111 16
C viewFields() 0 22 9
A viewFieldLine() 0 14 3
B viewMenu() 0 27 5
A getNameConst() 0 12 4
A view() 0 23 1
A getFileName() 0 9 2
A save() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like DeCaptchaWiki often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DeCaptchaWiki, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace jumper423\decaptcha\core;
4
5
/**
6
 * Class DeCaptchaAbstract.
7
 */
8
class DeCaptchaWiki
9
{
10
    private $texts = [];
11
    /**
12
     * @var DeCaptchaBase
13
     */
14
    private $class;
15
    private $lang = 'en';
16
17
    public function setLang($lang)
18
    {
19
        $this->lang = $lang;
20
    }
21
22
    public function __construct($class)
23
    {
24
        $this->class = $class;
25
        $this->texts = [
26
            'constructor_data' => [
27
                $class::ACTION_FIELD_KEY => '94f39af4bb295c40546fba5c932e0d32',
28
            ],
29
            'recognize_file'                                    => true,
30
            'recognize_data_file'                               => 'http://site.com/captcha.jpg',
31
            'recognize_data'                                    => [],
32
            'field_main_name_'.$class::ACTION_FIELD_KEY         => [
33
                'ru' => 'Ключ',
34
            ],
35
            'field_main_desc_'.$class::ACTION_FIELD_KEY => [
36
                'ru' => 'Ключ от учетной записи',
37
            ],
38
            'field_main_name_'.$class::ACTION_FIELD_LANGUAGE => [
39
                'ru' => 'Язык',
40
            ],
41
            'field_main_desc_'.$class::ACTION_FIELD_LANGUAGE => [
42
                'ru' => 'На каком языке текст на капче',
43
            ],
44
            'field_main_name_'.$class::ACTION_FIELD_FILE => [
45
                'ru' => 'Картинка',
46
            ],
47
            'field_main_desc_'.$class::ACTION_FIELD_FILE => [
48
                'ru' => 'Путь на файл с картинкой или ссылка на него',
49
            ],
50
            'field_main_name_'.$class::ACTION_FIELD_PHRASE => [
51
                'ru' => 'Несколько слов',
52
            ],
53
            'field_main_desc_'.$class::ACTION_FIELD_PHRASE => [
54
                'ru' => 'Работник должен ввести текст с одним или несколькими пробелами',
55
            ],
56
            'field_main_name_'.$class::ACTION_FIELD_REGSENSE => [
57
                'ru' => 'Регистр',
58
            ],
59
            'field_main_desc_'.$class::ACTION_FIELD_REGSENSE => [
60
                'ru' => 'Работник должен ввсести ответ с учетом регистра',
61
            ],
62
            'field_main_name_'.$class::ACTION_FIELD_NUMERIC => [
63
                'ru' => 'Символы',
64
            ],
65
            'field_main_desc_'.$class::ACTION_FIELD_NUMERIC => [
66
                'ru' => 'Какие символы используется в капче',
67
            ],
68
            'field_main_name_'.$class::ACTION_FIELD_CALC => [
69
                'ru' => 'Вычисление',
70
            ],
71
            'field_main_desc_'.$class::ACTION_FIELD_CALC => [
72
                'ru' => 'На капче изображенно математичекая выражение и её необходимо решить',
73
            ],
74
            'field_main_name_'.$class::ACTION_FIELD_MIN_LEN => [
75
                'ru' => 'Длина min',
76
            ],
77
            'field_main_desc_'.$class::ACTION_FIELD_MIN_LEN => [
78
                'ru' => 'Минимальная длина капчи',
79
            ],
80
            'field_main_name_'.$class::ACTION_FIELD_MAX_LEN => [
81
                'ru' => 'Длина max',
82
            ],
83
            'field_main_desc_'.$class::ACTION_FIELD_MAX_LEN => [
84
                'ru' => 'Максимальная длина капчи',
85
            ],
86
            'field_main_name_'.$class::ACTION_FIELD_QUESTION => [
87
                'ru' => 'Вопрос',
88
            ],
89
            'field_main_desc_'.$class::ACTION_FIELD_QUESTION => [
90
                'ru' => 'На изображении задан вопрос, работник должен написать ответ',
91
            ],
92
            'field_main_name_'.$class::ACTION_FIELD_IS_RUSSIAN => [
93
                'ru' => 'Кириллица',
94
            ],
95
            'field_main_desc_'.$class::ACTION_FIELD_IS_RUSSIAN => [
96
                'ru' => 'На изображении присутствуют русские символы',
97
            ],
98
            'field_main_name_'.$class::ACTION_FIELD_LANGUAGE => [
99
                'ru' => 'Язык',
100
            ],
101
            'field_main_desc_'.$class::ACTION_FIELD_LANGUAGE => [
102
                'ru' => 'Символы какого языка размещенны на капче',
103
            ],
104
            'field_main_name_'.$class::ACTION_FIELD_HEADER_ACAO => [
105
                'ru' => 'Кросс-доменный',
106
            ],
107
            'field_main_desc_'.$class::ACTION_FIELD_HEADER_ACAO => [
108
                'ru' => 'Необходимо для кросс-доменных AJAX запросов в браузерных приложениях.',
109
            ],
110
            'field_main_name_'.$class::ACTION_FIELD_INSTRUCTIONS => [
111
                'ru' => 'Инструкция',
112
            ],
113
            'field_main_desc_'.$class::ACTION_FIELD_INSTRUCTIONS => [
114
                'ru' => 'Текстовая капча или инструкция для прохождения капчи.',
115
            ],
116
            'field_main_name_'.$class::ACTION_FIELD_PINGBACK => [
117
                'ru' => 'Ответ на',
118
            ],
119
            'field_main_desc_'.$class::ACTION_FIELD_PINGBACK => [
120
                'ru' => 'Указание для сервера, что после распознания изображения, нужно отправить ответ на указанный адрес.',
121
            ],
122
            'field_main_name_'.$class::ACTION_FIELD_LABEL => [
123
                'ru' => 'От куда',
124
            ],
125
            'field_main_desc_'.$class::ACTION_FIELD_LABEL => [
126
                'ru' => 'Пояснение от куда пришла капча ("vk", "google", "recaptcha", "yandex", "mailru", "yahoo" и т.д.).',
127
            ],
128
            'field_main_name_'.$class::ACTION_FIELD_PAGEURL => [
129
                'ru' => 'Адрес',
130
            ],
131
            'field_main_desc_'.$class::ACTION_FIELD_PAGEURL => [
132
                'ru' => 'Адрес страницы на которой решается капча.',
133
            ],
134
            'field_main_name_'.$class::ACTION_FIELD_GOOGLEKEY => [
135
                'ru' => 'Google key',
136
            ],
137
            'field_main_desc_'.$class::ACTION_FIELD_GOOGLEKEY => [
138
                'ru' => 'Ключ-индентификатор рекапчи на целевой странице. <div class="g-recaptcha" data-sitekey="ВОТ_ЭТОТ"></div>',
139
            ],
140
            'field_main_name_'.$class::ACTION_FIELD_GOOGLETOKEN => [
141
                'ru' => 'Google token',
142
            ],
143
            'field_main_desc_'.$class::ACTION_FIELD_GOOGLETOKEN => [
144
                'ru' => 'Секретный токен для предыдущей версии рекапчи. В большинстве случаев сайты используют новую версию и этот токен не требуется. Секретный токен генерируется на сервере Google и вставляется на страницу в атрибуте data-stoken. Выглядит это примерно так: <script type="text/javascript" src="...." data-type="normal"  data-ray="..." async data-sitekey="..." data-stoken="ВОТ_ЭТОТ"></script> Токен действует пару минут после генерации, затем нужно снова зайти на страницу и получить его.',
145
            ],
146
            'field_main_name_'.$class::ACTION_FIELD_PROXYTYPE => [
147
                'ru' => 'Тип прокси',
148
            ],
149
            'field_main_desc_'.$class::ACTION_FIELD_PROXYTYPE => [
150
                'ru' => 'Тип прокси (http, socks4, ...)',
151
            ],
152
            'field_main_name_'.$class::ACTION_FIELD_PROXY => [
153
                'ru' => 'Адрес прокси',
154
            ],
155
            'field_main_desc_'.$class::ACTION_FIELD_PROXY => [
156
                'ru' => 'IP адрес прокси ipv4/ipv6.',
157
            ],
158
            'field_main_name_'.$class::ACTION_FIELD_PROXYPORT => [
159
                'ru' => 'Порт прокси',
160
            ],
161
            'field_main_desc_'.$class::ACTION_FIELD_PROXYPORT => [
162
                'ru' => 'Порт прокси.',
163
            ],
164
            'field_main_name_'.$class::ACTION_FIELD_PROXYLOGIN => [
165
                'ru' => 'Логин прокси',
166
            ],
167
            'field_main_desc_'.$class::ACTION_FIELD_PROXYLOGIN => [
168
                'ru' => 'Логин от прокси-сервера.',
169
            ],
170
            'field_main_name_'.$class::ACTION_FIELD_PROXYPASS => [
171
                'ru' => 'Пароль прокси',
172
            ],
173
            'field_main_desc_'.$class::ACTION_FIELD_PROXYPASS => [
174
                'ru' => 'Пароль от прокси-сервера.',
175
            ],
176
            'field_main_name_'.$class::ACTION_FIELD_USERAGENT => [
177
                'ru' => 'User-Agent браузера',
178
            ],
179
            'field_main_desc_'.$class::ACTION_FIELD_USERAGENT => [
180
                'ru' => 'User-Agent браузера, используемый в эмуляции. Необходимо использовать подпись современного браузера, иначе Google будет возвращать ошибку, требуя обновить браузер.',
181
            ],
182
            'field_main_name_'.$class::ACTION_FIELD_COOKIES => [
183
                'ru' => 'Куки',
184
            ],
185
            'field_main_desc_'.$class::ACTION_FIELD_COOKIES => [
186
                'ru' => 'Дополнительные cookies которые мы должны использовать во время взаимодействия с целевой страницей.',
187
            ],
188
            'table_th_name' => [
189
                'ru' => 'Название',
190
            ],
191
            'table_th_code' => [
192
                'ru' => 'Код',
193
            ],
194
            'table_th_type' => [
195
                'ru' => 'Тип',
196
            ],
197
            'table_th_req' => [
198
                'ru' => 'Обяз.', //Обязательное
199
            ],
200
            'table_th_def' => [
201
                'ru' => 'По ум.', //По умолчания
202
            ],
203
            'table_th_enum' => [
204
                'ru' => 'Возможные значения',
205
            ],
206
            'table_th_desc' => [
207
                'ru' => 'Описание',
208
            ],
209
            'slug_link' => [
210
                'ru' => 'Ссылка',
211
            ],
212
            'slug_link_to_service' => [
213
                'ru' => 'Ссылка на сервис',
214
            ],
215
            'slug_price' => [
216
                'ru' => 'Цены',
217
            ],
218
            'slug_service_desc' => [
219
                'ru' => 'Описание сервиса',
220
            ],
221
            'slug_recognize_desc' => [
222
                'ru' => 'Описание распознания',
223
            ],
224
            'slug_fields_desc' => [
225
                'ru' => 'Описание полей',
226
            ],
227
            'example' => [
228
                'ru' => 'Примеры',
229
            ],
230
            'example_initialization' => [
231
                'ru' => 'Инициализация',
232
            ],
233
            'example_initialization_desc' => [
234
                'ru' => 'Указываем ключ, обязательные и дополнительные параметры. Старайтесь по максимуму их заполнить это способствует более быстрому распознанию капчи.',
235
            ],
236
            'example_recognize' => [
237
                'ru' => 'Распознавание',
238
            ],
239
            'example_recognize_desc' => [
240
                'ru' => 'В первом параметре передаём ссылку или путь на файл с картинкой, во второй параметры распознания при необходимости переопределения тех которые были переданы при инициализации.',
241
            ],
242
            'example_nottrue' => [
243
                'ru' => 'Не верно распознано',
244
            ],
245
            'example_nottrue_desc' => [
246
                'ru' => 'Если Вы сможете понять что ответ которые пришёл не верные. Обязательно добавьте ниже написанный код. Это Вам съекономит деньги.',
247
            ],
248
            'example_balance' => [
249
                'ru' => 'Баланс',
250
            ],
251
            'example_error_lang_if' => [
252
                'ru' => true,
253
                'en' => false,
254
            ],
255
            'example_error_lang' => [
256
                'ru' => 'Язык ошибки',
257
            ],
258
            'example_error_lang_desc' => [
259
                'ru' => 'По умолчанию ошибки на англиском языке, если необходимо переоперелить, сделайте следующее',
260
            ],
261
            'example_error_interception' => [
262
                'ru' => 'Перехват ошибки',
263
            ],
264
            'example_error_interception_desc' => [
265
                'ru' => 'При желании Вы можете перехватывать ошибку, но для этого надо вызвать setCauseAnError',
266
            ],
267
            'install' => [
268
                'ru' => 'Установка',
269
            ],
270
            'install_preferred' => [
271
                'ru' => 'Предпочтительный способ установить это расширение через',
272
            ],
273
            'install_start' => [
274
                'ru' => 'Либо запустить',
275
            ],
276
            'install_add' => [
277
                'ru' => 'или добавить',
278
            ],
279
            'install_add_file' => [
280
                'ru' => 'в файл',
281
            ],
282
            'slug_menu' => [
283
                'ru' => 'Меню',
284
                'en' => 'Menu',
285
            ],
286
            'slug_menu_main' => [
287
                'ru' => 'Главная',
288
            ],
289
            'slug_menu_another' => [
290
                'ru' => 'Документация на англиском языке',
291
                'en' => 'Документация на русском языке',
292
            ],
293
            'slug_menu_anchor' => [
294
                'ru' => 'Якоря',
295
            ],
296
            'slug_menu_from_service' => [
297
                'ru' => 'Другой функционал от сервиса',
298
            ],
299
        ];
300
    }
301
302
    /**
303
     * @param string|array $name
304
     * @param string|array $value
305
     */
306
    public function setText($name, $value)
307
    {
308
        if (is_array($name)) {
309
            $name = implode('_', $name);
310
        }
311
        $this->texts[$name] = $value;
312
    }
313
314
    /**
315
     * @param string|array $name
316
     * @param string       $separator
317
     *
318
     * @return string|array
319
     */
320
    public function getText($name, $separator = '; ')
321
    {
322
        $getResult = function ($name, $texts) {
323
            if (is_array($name)) {
324
                $name = implode('_', $name);
325
            }
326
            if (!isset($texts[$name])) {
327
                return null;
328
            }
329
            if (is_array($texts[$name])) {
330
                if (isset($texts[$name][$this->lang])) {
331
                    return $texts[$name][$this->lang];
332
                }
333
334
                return array_values($texts[$name])[0];
335
            }
336
337
            return $texts[$name];
338
        };
339
        $result = $getResult($name, $this->texts);
340
        if (is_array($result)) {
341
            if ($separator) {
342
                $result = implode($separator, $result);
343
            }
344
        }
345
346
        return $result;
347
    }
348
349
    private function viewInstall()
350
    {
351
        $str = "{$this->getText(['install', 'preferred'])} [composer](http://getcomposer.org/download/).".PHP_EOL;
352
        $str .= PHP_EOL;
353
        $str .= "{$this->getText(['install', 'start'])}".PHP_EOL;
354
        $str .= '```'.PHP_EOL;
355
        $str .= 'php composer.phar require --prefer-dist jumper423/decaptcha "*"'.PHP_EOL;
356
        $str .= '```'.PHP_EOL;
357
        $str .= "{$this->getText(['install', 'add'])}".PHP_EOL;
358
        $str .= '```'.PHP_EOL;
359
        $str .= '"jumper423/decaptcha": "*"'.PHP_EOL;
360
        $str .= '```'.PHP_EOL;
361
        $str .= "{$this->getText(['install', 'add', 'file'])} `composer.json`.".PHP_EOL;
362
363
        return $str;
364
    }
365
366
    private function viewExamples()
367
    {
368
        $class = $this->class;
369
        $rc = (new \ReflectionClass($class));
370
371
        $str = "#####{$this->getText(['example', 'initialization'])}".PHP_EOL;
372
        $str .= "{$this->getText(['example', 'initialization', 'desc'])}".PHP_EOL;
373
        $str .= '```'.PHP_EOL;
374
        $str .= "use {$rc->getName()};".PHP_EOL;
0 ignored issues
show
Bug introduced by
Consider using $rc->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
375
        $str .= ''.PHP_EOL;
376
        $str .= '$captcha = new '.$rc->getShortName().'(['.PHP_EOL;
377
        foreach ($this->texts['constructor_data'] as $key => $val) {
378
            $str .= "    {$rc->getShortName()}::{$this->getNameConst('ACTION_FIELD_', $key)} => ";
379
            if (is_string($val)) {
380
                $str .= "'{$val}'";
381
            } else {
382
                $str .= "{$val}";
383
            }
384
            $str .= ','.PHP_EOL;
385
        }
386
        $str .= ']);'.PHP_EOL;
387
        $str .= '```'.PHP_EOL;
388
389
        $str .= "#####{$this->getText(['example', 'recognize'])}".PHP_EOL;
390
        $str .= "{$this->getText(['example', 'recognize', 'desc'])}".PHP_EOL;
391
        $str .= '```'.PHP_EOL;
392
        $str .= 'if ($captcha->recognize(';
393 View Code Duplication
        if ($this->texts['recognize_file']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
394
            $str .= "'{$this->getText(['recognize', 'data', 'file'])}'";
395
        }
396 View Code Duplication
        if ($this->texts['recognize_data']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
397
            if ($this->texts['recognize_file']) {
398
                $str .= ', ';
399
            }
400
            $str .= '['.PHP_EOL;
401
            foreach ($this->texts['recognize_data'] as $key => $val) {
402
                $str .= "    {$rc->getShortName()}::{$this->getNameConst('ACTION_FIELD_', $key)} => ";
403
                if (is_string($val)) {
404
                    $str .= "'{$val}'";
405
                } else {
406
                    $str .= "{$val}";
407
                }
408
                $str .= ','.PHP_EOL;
409
            }
410
            $str .= ']';
411
        }
412
        $str .= ')) {'.PHP_EOL;
413
        $str .= '    $code = $captcha->getCode();'.PHP_EOL;
414
        $str .= '} else {'.PHP_EOL;
415
        $str .= '    $error = $captcha->getError();'.PHP_EOL;
416
        $str .= '}'.PHP_EOL;
417
        $str .= '```'.PHP_EOL;
418
419
        if (in_array('notTrue', get_class_methods($class))) {
420
            $str .= "#####{$this->getText(['example', 'nottrue'])}".PHP_EOL;
421
            $str .= "{$this->getText(['example', 'nottrue', 'desc'])}".PHP_EOL;
422
            $str .= '```'.PHP_EOL;
423
            $str .= '$captcha->notTrue();'.PHP_EOL;
424
            $str .= '```'.PHP_EOL;
425
        }
426
427
        if (in_array('getBalance', get_class_methods($class))) {
428
            $str .= "#####{$this->getText(['example', 'balance'])}".PHP_EOL;
429
            $str .= '```'.PHP_EOL;
430
            $str .= '$balance = $captcha->getBalance();'.PHP_EOL;
431
            $str .= '```'.PHP_EOL;
432
        }
433
434
        if ($this->getText(['example', 'error', 'lang', 'if'])) {
435
            $str .= "#####{$this->getText(['example', 'error', 'lang'])}".PHP_EOL;
436
            $str .= "{$this->getText(['example', 'error', 'lang', 'desc'])}".PHP_EOL;
437
            $str .= '```'.PHP_EOL;
438
            $str .= '$captcha->setErrorLang(\jumper423\decaptcha\core\DeCaptchaErrors::LANG_RU);'.PHP_EOL;
439
            $str .= '```'.PHP_EOL;
440
        }
441
442
        $str .= "#####{$this->getText(['example', 'error', 'interception'])}".PHP_EOL;
443
        $str .= "{$this->getText(['example', 'error', 'interception', 'desc'])}".PHP_EOL;
444
        $str .= '```'.PHP_EOL;
445
        $str .= '$captcha->setCauseAnError(true);'.PHP_EOL;
446
        $str .= PHP_EOL;
447
        $str .= 'try {'.PHP_EOL;
448
        $str .= '    $captcha->recognize(';
449 View Code Duplication
        if ($this->texts['recognize_file']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
450
            $str .= "'{$this->getText(['recognize', 'data', 'file'])}'";
451
        }
452 View Code Duplication
        if ($this->texts['recognize_data']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
453
            if ($this->texts['recognize_file']) {
454
                $str .= ', ';
455
            }
456
            $str .= '['.PHP_EOL;
457
            foreach ($this->texts['recognize_data'] as $key => $val) {
458
                $str .= "       {$rc->getShortName()}::{$this->getNameConst('ACTION_FIELD_', $key)} => ";
459
                if (is_string($val)) {
460
                    $str .= "'{$val}'";
461
                } else {
462
                    $str .= "{$val}";
463
                }
464
                $str .= ','.PHP_EOL;
465
            }
466
            $str .= '    ]';
467
        }
468
        $str .= ');'.PHP_EOL;
469
        $str .= '    $code = $captcha->getCode();'.PHP_EOL;
470
        $str .= '} catch (\jumper423\decaptcha\core\DeCaptchaErrors $e) {'.PHP_EOL;
471
        $str .= '    ...'.PHP_EOL;
472
        $str .= '}'.PHP_EOL;
473
        $str .= '```'.PHP_EOL;
474
475
        return $str;
476
    }
477
478
    private function viewFields()
479
    {
480
        $class = $this->class;
481
        $str = " {$this->getText(['table', 'th', 'name'])} | {$this->getText(['table', 'th', 'code'])} | {$this->getText(['table', 'th', 'type'])} | {$this->getText(['table', 'th', 'req'])} | {$this->getText(['table', 'th', 'def'])} | {$this->getText(['table', 'th', 'enum'])} | {$this->getText(['table', 'th', 'desc'])} ".PHP_EOL;
482
        $str .= ' --- | --- | --- | --- | --- | --- | --- '.PHP_EOL;
483
        foreach ($this->class->actions[$class::ACTION_RECOGNIZE][$class::ACTION_FIELDS] as $param => $setting) {
484
            if (array_key_exists($class::ACTION_FIELDS, $setting) && is_array($setting[$class::ACTION_FIELDS])) {
485
                foreach ($setting[$class::ACTION_FIELDS] as $param1 => $setting1) {
486
                    if (array_key_exists($class::PARAM_SLUG_NOTWIKI, $setting1) && $setting1[$class::PARAM_SLUG_NOTWIKI] === true) {
487
                        continue;
488
                    }
489
                    $str .= $this->viewFieldLine($param1, $setting1);
490
                }
491
            }
492
            if (array_key_exists($class::PARAM_SLUG_NOTWIKI, $setting) && $setting[$class::PARAM_SLUG_NOTWIKI] === true) {
493
                continue;
494
            }
495
            $str .= $this->viewFieldLine($param, $setting);
496
        }
497
498
        return $str;
499
    }
500
501
    private function viewFieldLine($param, $setting)
502
    {
503
        $class = $this->class;
504
        $str = " {$this->getText(['field', 'main', 'name', $param])} |";
505
        $str .= " {$this->getNameConst('ACTION_FIELD_', $param)} |";
506
        $str .= ' '.substr($this->getNameConst('PARAM_FIELD_TYPE_', $setting[$class::PARAM_SLUG_TYPE]), 17).' |';
507
        $str .= ' '.(array_key_exists($class::PARAM_SLUG_REQUIRE, $setting) ? '+' : '-').' |';
508
        $str .= ' '.(array_key_exists($class::PARAM_SLUG_DEFAULT, $setting) ? $setting[$class::PARAM_SLUG_DEFAULT] : '').' |';
509
        $str .= " {$this->getText(['field', 'slug', $class::PARAM_SLUG_ENUM, $param])} |";
510
        $str .= " {$this->getText(['field', 'main', 'desc', $param])} |";
511
        $str .= PHP_EOL;
512
513
        return $str;
514
    }
515
516
    private function viewMenu()
517
    {
518
        $str = "+ [{$this->getText(['slug','menu','main'])}](../blob/master/docs/README-{$this->lang}.md)".PHP_EOL;
519
        $str .= "+ [{$this->getText(['slug','menu','another'])}](../blob/master/docs/" . $this->getFileName($this->lang == 'ru' ? 'en' : 'ru') . ')'.PHP_EOL;
520
        $str .= "+ {$this->getText(['slug','menu','anchor'])}".PHP_EOL;
521
        foreach ([
522
                     ['slug', 'link'],
523
                     ['slug', 'service', 'desc'],
524
                     ['slug', 'price'],
525
                     ['slug', 'recognize', 'desc'],
526
                     ['install'],
527
                     ['example'],
528
                     ['slug', 'fields', 'desc']
529
                 ] as $anchor) {
530
            $str .= "  + [{$this->getText($anchor)}](#".implode('-', explode(' ', $this->getText($anchor))).")".PHP_EOL;
531
        }
532
        if ($this->getText(['menu','from_service'])) {
533
            $str .= "+ {$this->getText(['slug','menu','from_service'])}" . PHP_EOL;
534
            foreach ($this->texts['menu_from_service'] as $fromServiceClass) {
535
                $fromServiceObject = new $fromServiceClass([]);
536
                $fromServiceObjectWiki = $fromServiceObject->getWiki($this->lang);
537
                $str .= "  + [{$fromServiceObjectWiki->getText(['service', 'name'])}](../blob/master/docs/{$fromServiceObjectWiki->getFileName()})" . PHP_EOL;
538
            }
539
        }
540
541
        return $str;
542
    }
543
544
    private function getNameConst($keyMask, $value)
545
    {
546
        $class = $this->class;
547
        $constants = (new \ReflectionClass($class))->getConstants();
548
        foreach ($constants as $key => $val) {
549
            if (stripos($key, $keyMask) !== false && $val === $value) {
550
                return $key;
551
            }
552
        }
553
554
        return null;
555
    }
556
557
    public function view()
558
    {
559
        $str = $this->getText(['service', 'name']).PHP_EOL;
560
        $str .= '=============='.PHP_EOL;
561
        $str .= "###{$this->getText(['slug', 'menu'])}".PHP_EOL;
562
        $str .= $this->viewMenu().PHP_EOL.PHP_EOL;
563
        $str .= "###{$this->getText(['slug', 'link'])}".PHP_EOL;
564
        $str .= "[{$this->getText(['slug', 'link', 'to_service'])} {$this->getText(['service', 'name'])}]({$this->getText(['service', 'href'])})".PHP_EOL.PHP_EOL;
565
        $str .= "###{$this->getText(['slug', 'service', 'desc'])}".PHP_EOL;
566
        $str .= "{$this->getText(['service', 'desc'])}".PHP_EOL.PHP_EOL;
567
        $str .= "###{$this->getText(['slug', 'price'])}".PHP_EOL;
568
        $str .= "{$this->getText(['recognize', 'price'])}".PHP_EOL.PHP_EOL;
569
        $str .= "###{$this->getText(['slug', 'recognize', 'desc'])}".PHP_EOL;
570
        $str .= "{$this->getText(['recognize', 'desc'])}".PHP_EOL.PHP_EOL;
571
        $str .= "###{$this->getText(['install'])}".PHP_EOL;
572
        $str .= "{$this->viewInstall()}".PHP_EOL.PHP_EOL;
573
        $str .= "###{$this->getText(['example'])}".PHP_EOL;
574
        $str .= "{$this->viewExamples()}".PHP_EOL.PHP_EOL;
575
        $str .= "###{$this->getText(['slug', 'fields', 'desc'])}".PHP_EOL;
576
        $str .= $this->viewFields().PHP_EOL;
577
578
        return $str;
579
    }
580
581
    public function getFileName($lang = null)
582
    {
583
        if (is_null($lang)) {
584
            $lang = $this->lang;
585
        }
586
        $class = $this->class;
587
588
        return (new \ReflectionClass($class))->getShortName().'-'.$lang.'.md';
589
    }
590
591
    public function save()
592
    {
593
        file_put_contents(__DIR__.'/../../docs/'.$this->getFileName(), $this->view());
594
    }
595
}
596