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