Completed
Pull Request — master (#55)
by Julien
07:42
created

Question::ask()   F

Complexity

Conditions 20
Paths 162

Size

Total Lines 70
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 46
nc 162
nop 0
dl 0
loc 70
rs 3.65
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
4
namespace TheAentMachine\Helper;
5
6
use Symfony\Component\Console\Question\Question as SymfonyQuestion;
7
8
/**
9
 * A helper class to easily create questions.
10
 */
11
class Question extends BaseQuestion
12
{
13
    /** @var bool */
14
    private $compulsory = false;
15
    /** @var callable|null */
16
    private $validator;
17
    /** @var bool */
18
    private $yesNoQuestion = false;
19
20
    public function setDefault(string $default): self
21
    {
22
        $this->default = $default;
23
        return $this;
24
    }
25
26
    public function setHelpText(string $helpText): self
27
    {
28
        $this->helpText = $helpText;
29
        return $this;
30
    }
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 yesNoQuestion(): self
45
    {
46
        $this->yesNoQuestion = true;
47
        return $this;
48
    }
49
50
    public function ask(): string
51
    {
52
        $text = $this->question;
53
        if ($this->helpText) {
54
            $text .= ' (? for help)';
55
        }
56
        if ($this->default) {
57
            if (!$this->yesNoQuestion) {
58
                $text .= ' [' . $this->default . ']';
59
            } elseif ($this->default === 'y') {
60
                $text .= ' [Y/n]';
61
            } elseif ($this->default === 'n') {
62
                $text .= ' [y/N]';
63
            } else {
64
                throw new \InvalidArgumentException('Default value must be "y" or "n".');
65
            }
66
        } elseif ($this->yesNoQuestion) {
67
            $text .= ' [y/n]';
68
        }
69
        $text .= ': ';
70
71
        $question = new SymfonyQuestion($text, $this->default);
72
73
        $validator = $this->validator;
74
75
        if ($this->yesNoQuestion) {
76
            $validator = function (?string $response) use ($validator) {
77
                $response = $response ?? '';
78
                $response = \strtolower(trim($response));
79
                if (!\in_array($response, ['y', 'n', 'yes', 'no'])) {
80
                    throw new \InvalidArgumentException('Answer must be "y" or "n"');
81
                }
82
                $response = \in_array($response, ['y', 'yes']) ? '1' : '';
83
                return $validator ? $validator($response) : $response;
84
            };
85
        }
86
87
        if ($this->helpText !== null) {
88
            $validator = function (?string $response) use ($validator) {
89
                $response = $response ?? '';
90
                if (trim($response) === '?') {
91
                    $this->output->writeln($this->helpText ?: '');
92
                    return '?';
93
                }
94
                return $validator ? $validator($response) : $response;
95
            };
96
        }
97
98
        if ($this->compulsory) {
99
            $validator = function (?string $response) use ($validator) {
100
                $response = $response ?? '';
101
                if (trim($response) === '') {
102
                    throw new \InvalidArgumentException('This field is compulsory.');
103
                }
104
                return $validator ? $validator($response) : $response;
105
            };
106
        }
107
108
        $question->setValidator($validator);
109
110
        do {
111
            $answer = $this->helper->ask($this->input, $this->output, $question);
112
        } while ($this->helpText !== null && $answer === '?');
113
114
        if ($this->printAnswer) {
115
            $this->output->writeln("<info>Your answer: $answer</info>");
116
            $this->spacer();
117
        }
118
119
        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...
120
    }
121
}
122