• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tempestphp / tempest-framework / 11924655642

19 Nov 2024 12:37PM UTC coverage: 81.705% (-0.2%) from 81.946%
11924655642

push

github

web-flow
chore(core): framework installer improvements (#752)

1 of 17 new or added lines in 2 files covered. (5.88%)

56 existing lines in 5 files now uncovered.

7869 of 9631 relevant lines covered (81.7%)

51.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.23
/src/Tempest/Console/src/GenericConsole.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\Console;
6

7
use Closure;
8
use Tempest\Console\Actions\ExecuteConsoleCommand;
9
use Tempest\Console\Components\Interactive\ConfirmComponent;
10
use Tempest\Console\Components\Interactive\MultipleChoiceComponent;
11
use Tempest\Console\Components\Interactive\PasswordComponent;
12
use Tempest\Console\Components\Interactive\ProgressBarComponent;
13
use Tempest\Console\Components\Interactive\SearchComponent;
14
use Tempest\Console\Components\Interactive\SingleChoiceComponent;
15
use Tempest\Console\Components\Interactive\TextBoxComponent;
16
use Tempest\Console\Components\InteractiveComponentRenderer;
17
use Tempest\Console\Exceptions\UnsupportedComponent;
18
use Tempest\Console\Highlight\TempestConsoleLanguage\TempestConsoleLanguage;
19
use Tempest\Console\Input\ConsoleArgumentBag;
20
use Tempest\Container\Tag;
21
use Tempest\Highlight\Highlighter;
22
use Tempest\Highlight\Language;
23

24
final class GenericConsole implements Console
25
{
26
    private ?string $label = null;
27

28
    private bool $isForced = false;
29

30
    private bool $supportsTty = true;
31

32
    private bool $supportsPrompting = true;
33

34
    private ?InteractiveComponentRenderer $componentRenderer = null;
35

36
    public function __construct(
166✔
37
        private readonly OutputBuffer $output,
38
        private readonly InputBuffer $input,
39
        #[Tag('console')]
40
        private readonly Highlighter $highlighter,
41
        private readonly ExecuteConsoleCommand $executeConsoleCommand,
42
        private readonly ConsoleArgumentBag $argumentBag
43
    ) {
44
    }
166✔
45

46
    public function call(string $command): ExitCode|int
1✔
47
    {
48
        return ($this->executeConsoleCommand)($command);
1✔
49
    }
50

51
    public function setComponentRenderer(InteractiveComponentRenderer $componentRenderer): self
74✔
52
    {
53
        $this->componentRenderer = $componentRenderer;
74✔
54

55
        return $this;
74✔
56
    }
57

58
    public function setForced(): self
6✔
59
    {
60
        $this->isForced = true;
6✔
61

62
        return $this;
6✔
63
    }
64

65
    public function disableTty(): self
×
66
    {
67
        $this->supportsTty = false;
×
68

69
        return $this;
×
70
    }
71

72
    public function disablePrompting(): self
8✔
73
    {
74
        $this->supportsPrompting = false;
8✔
75

76
        return $this;
8✔
77
    }
78

79
    public function read(int $bytes): string
×
80
    {
81
        if (! $this->supportsPrompting()) {
×
82
            return '';
×
83
        }
84

85
        return $this->input->read($bytes);
×
86
    }
87

88
    public function readln(): string
36✔
89
    {
90
        if (! $this->supportsPrompting()) {
36✔
91
            return '';
×
92
        }
93

94
        return $this->input->readln();
36✔
95
    }
96

97
    public function write(string $contents): static
145✔
98
    {
99
        $this->writeWithLanguage($contents, new TempestConsoleLanguage());
145✔
100

101
        return $this;
145✔
102
    }
103

104
    public function writeln(string $line = ''): static
134✔
105
    {
106
        $this->write($line . PHP_EOL);
134✔
107

108
        return $this;
134✔
109
    }
110

111
    public function writeWithLanguage(string $contents, Language $language): Console
146✔
112
    {
113
        if ($this->label) {
146✔
114
            $contents = "<h2>{$this->label}</h2> {$contents}";
4✔
115
        }
116

117
        $this->output->write($this->highlighter->parse($contents, $language));
146✔
118

119
        return $this;
146✔
120
    }
121

122
    public function info(string $line): self
8✔
123
    {
124
        $this->writeln("<em>{$line}</em>");
8✔
125

126
        return $this;
8✔
127
    }
128

129
    public function error(string $line): self
7✔
130
    {
131
        $this->writeln("<error>{$line}</error>");
7✔
132

133
        return $this;
7✔
134
    }
135

136
    public function success(string $line): self
31✔
137
    {
138
        $this->writeln("<success>{$line}</success>");
31✔
139

140
        return $this;
31✔
141
    }
142

143
    public function withLabel(string $label): self
4✔
144
    {
145
        $clone = clone $this;
4✔
146

147
        $clone->label = $label;
4✔
148

149
        return $clone;
4✔
150
    }
151

152
    public function when(mixed $expression, callable $callback): self
3✔
153
    {
154
        if ($expression) {
3✔
155
            $callback($this);
3✔
156
        }
157

158
        return $this;
3✔
159
    }
160

161
    public function component(InteractiveConsoleComponent $component, array $validation = []): mixed
45✔
162
    {
163
        if ($this->supportsTty()) {
45✔
164
            return $this->componentRenderer->render($this, $component, $validation);
×
165
        }
166

167
        if ($component instanceof HasStaticComponent) {
45✔
168
            return $component->getStaticComponent()->render($this);
45✔
169
        }
170

171
        throw new UnsupportedComponent($component);
×
172
    }
173

174
    public function ask(
41✔
175
        string $question,
176
        ?array $options = null,
177
        mixed $default = null,
178
        bool $multiple = false,
179
        bool $asList = false,
180
        array $validation = [],
181
    ): null|string|array {
182
        if ($this->isForced && $default) {
41✔
NEW
183
            return $default;
×
184
        }
185

186
        if ($options === null || $options === []) {
41✔
187
            $component = new TextBoxComponent($question, $default);
19✔
188
        } elseif ($multiple) {
25✔
189
            $component = new MultipleChoiceComponent(
8✔
190
                question: $question,
8✔
191
                options: $options,
8✔
192
                default: is_array($default) ? $default : [$default],
8✔
193
            );
8✔
194
        } else {
195
            $component = new SingleChoiceComponent(
22✔
196
                question: $question,
22✔
197
                options: $options,
22✔
198
                default: $default,
22✔
199
                asList: $asList,
22✔
200
            );
22✔
201
        }
202

203
        return $this->component($component, $validation);
41✔
204
    }
205

206
    public function confirm(string $question, bool $default = false): bool
19✔
207
    {
208
        if ($this->isForced) {
19✔
209
            return true;
5✔
210
        }
211

212
        return $this->component(new ConfirmComponent($question, $default));
14✔
213
    }
214

215
    public function password(string $label = 'Password', bool $confirm = false): string
×
216
    {
217
        if (! $confirm) {
×
218
            return $this->component(new PasswordComponent($label));
×
219
        }
220

221
        $password = null;
×
222
        $passwordConfirm = null;
×
223

224
        while ($password === null || $password !== $passwordConfirm) {
×
225
            if ($password !== null) {
×
226
                $this->error("Passwords don't match");
×
227
            }
228

229
            $password = $this->component(new PasswordComponent($label));
×
230
            $passwordConfirm = $this->component(new PasswordComponent('Please confirm'));
×
231
        }
232

233
        return $password;
×
234
    }
235

236
    public function progressBar(iterable $data, Closure $handler): array
1✔
237
    {
238
        return $this->component(new ProgressBarComponent($data, $handler));
1✔
239
    }
240

241
    public function search(string $label, Closure $search, ?string $default = null): mixed
5✔
242
    {
243
        return $this->component(new SearchComponent($label, $search, $default));
5✔
244
    }
245

246
    public function supportsTty(): bool
45✔
247
    {
248
        if ($this->supportsTty === false) {
45✔
249
            return false;
×
250
        }
251

252
        if ($this->componentRenderer === null) {
45✔
253
            return false;
45✔
254
        }
255

256
        if (! $this->supportsPrompting()) {
×
257
            return false;
×
258
        }
259

260
        return (bool) shell_exec('which tput && which stty');
×
261
    }
262

263
    public function supportsPrompting(): bool
44✔
264
    {
265
        if ($this->supportsPrompting === false) {
44✔
266
            return false;
8✔
267
        }
268

269
        if ($this->argumentBag->get('interaction')?->value === false) {
36✔
270
            return false;
×
271
        }
272

273
        return true;
36✔
274
    }
275
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc