Passed
Branch master (72fde7)
by Observer
01:31
created

Setter   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 13
eloc 36
dl 0
loc 99
c 0
b 0
f 0
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A addAliase() 0 8 2
B parse() 0 35 9
A setLocale() 0 5 1
1
<?php
2
3
/**
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 * 
9
 * @package     ConsoleArgs
10
 * @copyright   2019 Podvirnyy Nikita (KRypt0n_)
11
 * @license     GNU GPLv3 <https://www.gnu.org/licenses/gpl-3.0.html>
12
 * @license     Enfesto Studio Group license <https://vk.com/topic-113350174_36400959>
13
 * @author      Podvirnyy Nikita (KRypt0n_)
14
 * 
15
 * Contacts:
16
 *
17
 * Email: <[email protected]>
18
 * VK:    vk.com/technomindlp
19
 *        vk.com/hphp_convertation
20
 * 
21
 */
22
23
namespace ConsoleArgs;
24
25
/**
26
 * Объект локализаций
27
 * Вы можете создать объект, указать в нём свои данные локализации и использовать его в командах, менеджере и т.п.
28
 */
29
class Locale
30
{
31
    public $execution_error            = '$callable must be any closure';
32
    public $command_type_exception     = '$command must be ConsoleArgs\Command object or instance of him';
33
    public $command_undefined_error    = 'You should write any available command';
34
    public $unselected_value_exception = 'You should write param value';
35
    public $param_type_exception       = '$param must be instance of ConsoleArgs\\Parameter interface';
36
    public $undefined_param_exception  = 'You must define this param';
37
    public $aliase_exists_exception    = 'This aliase already exists';
38
}
39
40
/**
41
 * Интерфейс всех параметров команд
42
 */
43
interface Parameter
44
{
45
    /**
46
     * Парсер значений
47
     */
48
    public function parse (array &$args);
49
}
50
51
/**
52
 * Объект флагов
53
 * Отвечает за создание флагов для команд
54
 */
55
class Flag implements Parameter
56
{
57
    public $names;
58
    protected $locale;
59
60
    /**
61
     * Конструктор
62
     * 
63
     * @param string $name - имя флага
64
     */
65
    public function __construct (string $name)
66
    {
67
        $this->names = [$name];
68
    }
69
70
    /**
71
     * Установка локализации
72
     * 
73
     * @param Locale $locale - объект локализации
74
     * 
75
     * @return Flag - возвращает сам себя
76
     */
77
    public function setLocale (Locale $locale): Param
78
    {
79
        $this->locale = $locale;
80
81
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type ConsoleArgs\Flag which is incompatible with the type-hinted return ConsoleArgs\Param.
Loading history...
82
    }
83
84
    /**
85
     * Добавление алиаса
86
     * 
87
     * @param string $name - алиас для добавления
88
     * 
89
     * @return Flag - возвращает сам себя
90
     */
91
    public function addAliase (string $name)
92
    {
93
        if (array_search ($name, $this->names) !== false)
94
            throw new \Exception ($this->locale->aliase_exists_exception);
95
96
        $this->names[] = $name;
97
98
        return $this;
99
    }
100
101
    /**
102
     * Парсер флагов
103
     * 
104
     * @param array &$args - массив аргументов для парсинга
105
     * 
106
     * Возвращает состояние флага
107
     */
108
    public function parse (array &$args)
109
    {
110
        $args = array_values ($args);
111
112
        foreach ($this->names as $name)
113
            if (($key = array_search ($name, $args)) !== false)
114
            {
115
                unset ($args[$key]);
116
                $args = array_values ($args);
117
118
                while ($this->parse ($args) !== false);
119
                
120
                return true;
121
            }
122
123
        return false;
124
    }
125
}
126
127
/**
128
 * Объект параметров
129
 * Отвечает за объявление параметров команд
130
 */
131
class Param implements Parameter
132
{
133
    public $names;
134
    public $defaultValue;
135
    public $required;
136
    protected $locale;
137
138
    /**
139
     * Конструктор
140
     * 
141
     * @param string $name - имя парамтера
142
     * [@param string $defaultValue = null] - значение параметра по умолчанию
143
     * [@param bool $required = false] - обязательно ли указание параметра
144
     */
145
    public function __construct (string $name, string $defaultValue = null, bool $required = false)
146
    {
147
        $this->names        = [$name];
148
        $this->defaultValue = $defaultValue;
149
        $this->required     = $required;
150
151
        $this->locale = new Locale;
152
    }
153
154
    /**
155
     * Установка локализации
156
     * 
157
     * @param Locale $locale - объект локализации
158
     * 
159
     * @return Param - возвращает сам себя
160
     */
161
    public function setLocale (Locale $locale): Param
162
    {
163
        $this->locale = $locale;
164
165
        return $this;
166
    }
167
168
    /**
169
     * Добавление алиаса
170
     * 
171
     * @param string $name - алиас для добавления
172
     * 
173
     * @return Param - возвращает сам себя
174
     */
175
    public function addAliase (string $name)
176
    {
177
        if (array_search ($name, $this->names) !== false)
178
            throw new \Exception ($this->locale->aliase_exists_exception);
179
180
        $this->names[] = $name;
181
182
        return $this;
183
    }
184
185
    /**
186
     * Парсер параметров
187
     * 
188
     * @param array &$args - массив аргументов для парсинга
189
     * 
190
     * Возвращает найденый параметр или массив найдёных параметров, если их было указано несколько
191
     */
192
    public function parse (array &$args)
193
    {
194
        $args = array_values ($args);
195
196
        foreach ($this->names as $name)
197
            if (($key = array_search ($name, $args)) !== false)
198
            {
199
                if (!isset ($args[$key + 1]))
200
                    throw new \Exception ($this->locale->unselected_value_exception);
201
202
                $param = [$args[$key + 1]];
203
204
                unset ($args[$key], $args[$key + 1]);
205
                $args = array_values ($args);
206
207
                try
208
                {
209
                    while (($altParam = $this->parse ($args)) !== $this->defaultValue)
210
                    {
211
                        if (is_array ($altParam))
212
                            $param = array_merge ($param, $altParam);
213
214
                        else $param[] = $altParam;
215
                    }
216
                }
217
218
                catch (\Throwable $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
219
                
220
                return sizeof ($param) == 1 ?
221
                    $param[0] : $param;
222
            }
223
224
        if ($this->required)
225
            throw new \Exception ($this->locale->undefined_param_exception);
226
227
        return $this->defaultValue;
228
    }
229
}
230
231
/**
232
 * Объект сеттеров
233
 * Отвечает за объявление сет-параметров команд
234
 */
235
class Setter implements Parameter
236
{
237
    public $names;
238
    public $separator;
239
    public $defaultValue;
240
    public $required;
241
    protected $locale;
242
243
    /**
244
     * Конструктор
245
     * 
246
     * @param string $name - имя сеттера
247
     * [@param string $separator = '='] - разделитель сеттера и значения
248
     * [@param string $defaultValue = null] - значение сеттера по умолчанию
249
     * [@param bool $required = false] - обязательно ли указание сеттера
250
     */
251
    public function __construct (string $name, string $separator = '=', string $defaultValue = null, bool $required = false)
252
    {
253
        $this->names        = [$name];
254
        $this->separator    = $separator;
255
        $this->defaultValue = $defaultValue;
256
        $this->required     = $required;
257
258
        $this->locale = new Locale;
259
    }
260
261
    /**
262
     * Установка локализации
263
     * 
264
     * @param Locale $locale - объект локализации
265
     * 
266
     * @return Param - возвращает сам себя
267
     */
268
    public function setLocale (Locale $locale): Param
269
    {
270
        $this->locale = $locale;
271
272
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type ConsoleArgs\Setter which is incompatible with the type-hinted return ConsoleArgs\Param.
Loading history...
273
    }
274
275
    /**
276
     * Добавление алиаса
277
     * 
278
     * @param string $name - алиас для добавления
279
     * 
280
     * @return Param - возвращает сам себя
281
     */
282
    public function addAliase (string $name)
283
    {
284
        if (array_search ($name, $this->names) !== false)
285
            throw new \Exception ($this->locale->aliase_exists_exception);
286
287
        $this->names[] = $name;
288
289
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type ConsoleArgs\Setter which is incompatible with the documented return type ConsoleArgs\Param.
Loading history...
290
    }
291
292
    /**
293
     * Парсер параметров
294
     * 
295
     * @param array &$args - массив аргументов для парсинга
296
     * 
297
     * Возвращает найденый параметр или массив найдёных параметров, если их было указано несколько
298
     */
299
    public function parse (array &$args)
300
    {
301
        $args = array_values ($args);
302
        $l    = strlen ($this->separator);
303
304
        foreach ($this->names as $name)
305
            foreach ($args as $id => $arg)
306
                if (substr ($arg, 0, ($pos = strlen ($name) + $l)) == $name . $this->separator)
307
                {
308
                    $param = [substr ($arg, $pos)];
309
310
                    unset ($args[$id]);
311
                    $args = array_values ($args);
312
313
                    try
314
                    {
315
                        while (($altParam = $this->parse ($args)) !== $this->defaultValue)
316
                        {
317
                            if (is_array ($altParam))
318
                                $param = array_merge ($param, $altParam);
319
    
320
                            else $param[] = $altParam;
321
                        }
322
                    }
323
324
                    catch (\Throwable $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
325
                    
326
                    return sizeof ($param) == 1 ?
327
                        $param[0] : $param;
328
                }
329
330
        if ($this->required)
331
            throw new \Exception ($this->locale->undefined_param_exception);
332
333
        return $this->defaultValue;
334
    }
335
}
336
337
/**
338
 * Объект команд
339
 * Отвечает за выполнение команд и работу с параметрами
340
 */
341
class Command
342
{
343
    public $name;
344
    public $callable;
345
    public $params = [];
346
347
    protected $locale;
348
349
    /**
350
     * Конструктор
351
     * 
352
     * @param string $name - имя команды
353
     * [@param \Closure $callable = null] - анонимная функция для выполнения
354
     */
355
    public function __construct (string $name, \Closure $callable = null)
356
    {
357
        $this->name   = $name;
358
        $this->locale = new Locale;
359
360
        if ($callable !== null)
361
            $this->callable = $callable;
362
    }
363
364
    /**
365
     * Установка локализации
366
     * 
367
     * @param Locale $locale - объект локализации
368
     * 
369
     * @return Command - возвращает сам себя
370
     */
371
    public function setLocale (Locale $locale): Command
372
    {
373
        $this->locale = $locale;
374
375
        return $this;
376
    }
377
378
    /**
379
     * Установка параметров
380
     * 
381
     * @param array $params - список параметров для установки
382
     * 
383
     * @return Command - возвращает сам себя
384
     */
385
    public function addParams (array $params): Command
386
    {
387
        foreach ($params as $param)
388
            if ($param instanceof Parameter)
389
                $this->params[current ($param->names)] = $param;
0 ignored issues
show
Bug introduced by
Accessing names on the interface ConsoleArgs\Parameter suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
390
391
            else throw new \Exception ($this->locale->param_type_exception);
392
393
        return $this;
394
    }
395
396
    /**
397
     * Парсинг параметров
398
     * 
399
     * @param array &$args - аргументы для парсинга
400
     * 
401
     * @return array - возвращает ассоциативный массив [параметр] => [значение]
402
     */
403
    public function getParams (array &$args): array
404
    {
405
        $params = array_combine (array_keys ($this->params), array_fill (0, sizeof ($this->params), null));
406
407
        foreach ($this->params as $name => $param)
408
            $params[$name] = $param->parse ($args);
409
410
        return $params;
411
    }
412
413
    /**
414
     * Выполнение команды
415
     * 
416
     * @param array &$args - аргументы команды
417
     */
418
    public function execute (array &$args)
419
    {
420
        if ($this->callable instanceof \Closure)
421
        {
422
            $params = $this->getParams ($args);
423
424
            return $this->callable->call ($this, array_values ($args), $params);
425
        }
426
427
        throw new \Exception ($this->locale->execution_error);
428
    }
429
}
430
431
/**
432
 * Объект дефолтной команды
433
 * Выполняется если менеджеру была передана некорректная команда
434
 */
435
class DefaultCommand extends Command
436
{
437
    /**
438
     * Конструктор
439
     * 
440
     * [@param \Closure $callable = null] - анонимная функция для выполнения
441
     */
442
    public function __construct (\Closure $callable = null)
443
    {
444
        if ($callable !== null)
445
            $this->callable = $callable;
446
    }
447
}
448
449
/**
450
 * Менеджер команд
451
 * Предоставляет возможность работы с командами через аргументы консоли
452
 */
453
class Manager
454
{
455
    public $commands = [];
456
    public $defaultCommand = null;
457
    protected $locale;
458
459
    /**
460
     * Конструктор
461
     * 
462
     * @param array $commands - список команд
463
     * [@param DefaultCommand $defaultCommand = null] - объект дефолтной команды
464
     */
465
    public function __construct (array $commands, DefaultCommand $defaultCommand = null)
466
    {
467
        $this->locale = new Locale;
468
        $this->defaultCommand = $defaultCommand;
469
470
        foreach ($commands as $command)
471
            if ($command instanceof Command)
472
                $this->commands[$command->name] = $command;
473
474
            else throw new \Exception ($this->locale->command_type_exception);
475
    }
476
477
    /**
478
     * Установка локализации
479
     * 
480
     * @param Locale $locale - объект локализации
481
     * 
482
     * @return Manager - возвращает сам себя
483
     */
484
    public function setLocale (Locale $locale): Manager
485
    {
486
        $this->locale = $locale;
487
488
        return $this;
489
    }
490
491
    /**
492
     * Установка дефолтной команды
493
     * 
494
     * @param DefaultCommand $defaultCommand - объект дефолтной команды
495
     * 
496
     * @return Manager - возвращает сам себя
497
     */
498
    public function setDefault (DefaultCommand $defaultCommand): Manager
499
    {
500
        $this->defaultCommand = $defaultCommand;
501
502
        return $this;
503
    }
504
505
    /**
506
     * Итерация выполнения по аргументам
507
     * 
508
     * @param array $args - список аргументов консоли
509
     */
510
    public function execute (array $args)
511
    {
512
        $args = array_values ($args);
513
514
        if (!isset ($args[0]))
515
        {
516
            if ($this->defaultCommand !== null)
517
                return $this->defaultCommand->execute ($args);
518
519
            else throw new \Exception ($this->locale->command_undefined_error);
520
        }
521
522
        $name = $args[0];
523
        $args = array_slice ($args, 1);
524
525
        if (!isset ($this->commands[$name]))
526
            return $this->defaultCommand !== null ?
527
                $this->defaultCommand->execute ($args) : false;
528
529
        return $this->commands[$name]->execute ($args);
530
    }
531
}
532