Passed
Pull Request — master (#26)
by David
02:11
created

AentHelper::question()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
4
namespace TheAentMachine;
5
6
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
7
use Symfony\Component\Console\Helper\FormatterHelper;
8
use Symfony\Component\Console\Helper\QuestionHelper;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Output\OutputInterface;
11
use Symfony\Component\Console\Question\Question;
12
use TheAentMachine\Registry\RegistryClient;
13
use TheAentMachine\Registry\TagsAnalyzer;
14
15
/**
16
 * A helper class for the most common questions asked in the console.
17
 */
18
class AentHelper
19
{
20
    /**
21
     * @var InputInterface
22
     */
23
    private $input;
24
    /**
25
     * @var OutputInterface
26
     */
27
    private $output;
28
    /**
29
     * @var QuestionHelper
30
     */
31
    private $questionHelper;
32
    /**
33
     * @var FormatterHelper
34
     */
35
    private $formatterHelper;
36
37
    public function __construct(InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, FormatterHelper $formatterHelper)
38
    {
39
40
        $this->input = $input;
41
        $this->output = $output;
42
        $this->questionHelper = $questionHelper;
43
        $this->formatterHelper = $formatterHelper;
44
    }
45
46
    private function registerStyle(): void
47
    {
48
        $outputStyle = new OutputFormatterStyle('black', 'cyan', ['bold']);
49
        $this->output->getFormatter()->setStyle('title', $outputStyle);
50
    }
51
52
    /**
53
     * Displays text in a big block
54
     */
55
    public function title(string $title): void
56
    {
57
        $this->registerStyle();
58
        $this->output->writeln($this->formatterHelper->formatBlock($title, 'title', true));
59
    }
60
61
    /**
62
     * Displays text in a small block
63
     */
64
    public function subTitle(string $title): void
65
    {
66
        $this->registerStyle();
67
        $this->output->writeln($this->formatterHelper->formatBlock($title, 'title', false));
68
    }
69
70
    public function askForServiceName(string $serviceName, string $applicationName = ''): string
71
    {
72
        $answer = $this->question("$applicationName service name")
73
            ->setDefault($serviceName)
74
            ->compulsory()
75
            ->setHelpText('The "service name" is used as an identifier for the container you are creating. It is also bound in Docker internal network DNS and can be used from other containers to reference your container.')
76
            ->setValidator(function (string $value) {
77
                $value = trim($value);
78
                if (!\preg_match('/^[a-zA-Z0-9_.-]+$/', $value)) {
79
                    throw new \InvalidArgumentException('Invalid service name "'.$value.'". Service names can contain alphanumeric characters, and "_", ".", "-".');
80
                }
81
                return $value;
82
            })
83
            ->ask();
84
85
        $this->output->writeln("<info>Service name: $answer</info>");
86
        $this->spacer();
87
88
        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...
89
    }
90
91
    public function spacer(): void
92
    {
93
        $this->output->writeln('');
94
    }
95
96
    public function askForTag(string $dockerHubImage, string $applicationName = ''): string
97
    {
98
        $registryClient = new RegistryClient();
99
        $availableVersions = $registryClient->getImageTagsOnDockerHub($dockerHubImage);
100
101
        $tagsAnalyzer = new TagsAnalyzer();
102
        $proposedTags = $tagsAnalyzer->filterBestTags($availableVersions);
103
        $default = $proposedTags[0] ?? null;
104
        $this->output->writeln("Please choose your $applicationName version.");
105
        if (!empty($proposedTags)) {
106
            $this->output->writeln('Possible values include: <info>'.\implode('</info>, <info>', $proposedTags).'</info>');
107
108
        }
109
        $this->output->writeln('Enter "v" to view all available versions, "?" for help');
110
        $question = new Question(
111
            "Select your $applicationName version [$default]: ",
112
            $default
113
        );
114
        $question->setAutocompleterValues($availableVersions);
115
        $question->setValidator(function (string $value) use ($availableVersions, $dockerHubImage) {
116
            $value = trim($value);
117
118
            if ($value === 'v') {
119
                $this->output->writeln('Available versions: <info>'.\implode('</info>, <info>', $availableVersions).'</info>');
120
                return 'v';
121
            }
122
123
            if ($value === '?') {
124
                $this->output->writeln("Please choose the version (i.e. the tag) of the $dockerHubImage image you are about to install. Press 'v' to view the list of available tags.");
125
                return '?';
126
            }
127
128
            if (!\in_array($value, $availableVersions)) {
129
                throw new \InvalidArgumentException("Version '$value' is invalid.");
130
            }
131
132
            return $value;
133
        });
134
        do {
135
            $version = $this->questionHelper->ask($this->input, $this->output, $question);
136
        } while ($version === 'v' || $version === '?');
137
138
        $this->output->writeln("<info>Selected version: $version</info>");
139
        $this->spacer();
140
141
        return $version;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $version 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...
142
    }
143
144
    public function question(string $question): \TheAentMachine\Helper\Question
145
    {
146
        return new \TheAentMachine\Helper\Question($this->questionHelper, $this->input, $this->output, $question);
147
    }
148
}
149