Completed
Push — master ( 0c8701...84a040 )
by Julien
13s
created

Question::ask()   D

Complexity

Conditions 19
Paths 82

Size

Total Lines 65
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
eloc 43
nc 82
nop 0
dl 0
loc 65
rs 4.5166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace TheAentMachine\Helper;
4
5
use Symfony\Component\Console\Helper\QuestionHelper;
6
use Symfony\Component\Console\Input\InputInterface;
7
use Symfony\Component\Console\Output\OutputInterface;
8
9
/**
10
 * A helper class to easily create questions.
11
 */
12
class Question extends BaseQuestion
13
{
14
    private $default;
15
    /**
16
     * @var bool
17
     */
18
    private $compulsory = false;
19
    /**
20
     * @var callable|null
21
     */
22
    private $validator;
23
    /**
24
     * @var string|null
25
     */
26
    private $helpText;
27
    /**
28
     * @var bool
29
     */
30
    private $yesNoQuestion = false;
31
32
    public function compulsory(): self
33
    {
34
        $this->compulsory = true;
35
        return $this;
36
    }
37
38
    public function setValidator(callable $validator): self
39
    {
40
        $this->validator = $validator;
41
        return $this;
42
    }
43
44
    public function setHelpText(string $helpText): self
45
    {
46
        $this->helpText = $helpText;
47
        return $this;
48
    }
49
50
    public function setDefault(string $default): self
51
    {
52
        $this->default = $default;
53
        return $this;
54
    }
55
56
    public function yesNoQuestion(): self
57
    {
58
        $this->yesNoQuestion = true;
59
        return $this;
60
    }
61
62
    public function ask(): string
63
    {
64
        $text = $this->question;
65
        if ($this->helpText) {
66
            $text .= ' (? for help)';
67
        }
68
        if ($this->default) {
69
            if (!$this->yesNoQuestion) {
70
                $text .= ' [' . $this->default . ']';
71
            } elseif ($this->default === 'y') {
72
                $text .= ' [Y/n]';
73
            } elseif ($this->default === 'n') {
74
                $text .= ' [y/N]';
75
            } else {
76
                throw new \InvalidArgumentException('Default value must be "y" or "n".');
77
            }
78
        } elseif ($this->yesNoQuestion) {
79
            $text .= ' [y/n]';
80
        }
81
        $text .= ': ';
82
83
        $question = new \Symfony\Component\Console\Question\Question($text, $this->default);
84
85
        $validator = $this->validator;
86
87
        if ($this->yesNoQuestion) {
88
            $validator = function (?string $response) use ($validator) {
89
                $response = $response ?? '';
90
                $response = \strtolower(trim($response));
91
                if (!\in_array($response, ['y', 'n', 'yes', 'no'])) {
92
                    throw new \InvalidArgumentException('Answer must be "y" or "n"');
93
                }
94
                $response = \in_array($response, ['y', 'yes']) ? '1' : '';
95
                return $validator ? $validator($response) : $response;
96
            };
97
        }
98
99
        if ($this->helpText !== null) {
100
            $validator = function (?string $response) use ($validator) {
101
                $response = $response ?? '';
102
                if (trim($response) === '?') {
103
                    $this->output->writeln($this->helpText ?: '');
104
                    return '?';
105
                }
106
                return $validator ? $validator($response) : $response;
107
            };
108
        }
109
110
        if ($this->compulsory) {
111
            $validator = function (?string $response) use ($validator) {
112
                $response = $response ?? '';
113
                if (trim($response) === '') {
114
                    throw new \InvalidArgumentException('This field is compulsory.');
115
                }
116
                return $validator ? $validator($response) : $response;
117
            };
118
        }
119
120
        $question->setValidator($validator);
121
122
        do {
123
            $answer = $this->helper->ask($this->input, $this->output, $question);
124
        } while ($this->helpText !== null && $answer === '?');
125
126
        return $answer;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $answer could return the type null|boolean which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
127
    }
128
}
129