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

tempestphp / tempest-framework / 11714560237

06 Nov 2024 06:46PM UTC coverage: 82.608% (+0.003%) from 82.605%
11714560237

push

github

web-flow
feat(container): support injecting properties using `#[Inject]` (#690)

6 of 6 new or added lines in 2 files covered. (100.0%)

95 existing lines in 9 files now uncovered.

7210 of 8728 relevant lines covered (82.61%)

49.34 hits per line

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

75.0
/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

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

27
    private bool $isForced = false;
28

29
    private bool $supportsTty = true;
30

31
    private bool $supportsPrompting = true;
32

33
    private ?InteractiveComponentRenderer $componentRenderer = null;
34

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

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

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

54
        return $this;
56✔
55
    }
56

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

61
        return $this;
6✔
62
    }
63

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

UNCOV
68
        return $this;
×
69
    }
70

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

75
        return $this;
8✔
76
    }
77

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

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

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

93
        return $this->input->readln();
27✔
94
    }
95

96
    public function write(string $contents): static
129✔
97
    {
98
        if ($this->label) {
129✔
99
            $contents = "<h2>{$this->label}</h2> {$contents}";
4✔
100
        }
101

102
        $this->output->write($this->highlighter->parse($contents, new TempestConsoleLanguage()));
129✔
103

104
        return $this;
129✔
105
    }
106

107
    public function writeln(string $line = ''): static
118✔
108
    {
109
        $this->write($line . PHP_EOL);
118✔
110

111
        return $this;
118✔
112
    }
113

114
    public function info(string $line): self
6✔
115
    {
116
        $this->writeln("<em>{$line}</em>");
6✔
117

118
        return $this;
6✔
119
    }
120

121
    public function error(string $line): self
7✔
122
    {
123
        $this->writeln("<error>{$line}</error>");
7✔
124

125
        return $this;
7✔
126
    }
127

128
    public function success(string $line): self
21✔
129
    {
130
        $this->writeln("<success>{$line}</success>");
21✔
131

132
        return $this;
21✔
133
    }
134

135
    public function withLabel(string $label): self
4✔
136
    {
137
        $clone = clone $this;
4✔
138

139
        $clone->label = $label;
4✔
140

141
        return $clone;
4✔
142
    }
143

144
    public function when(mixed $expression, callable $callback): self
3✔
145
    {
146
        if ($expression) {
3✔
147
            $callback($this);
3✔
148
        }
149

150
        return $this;
3✔
151
    }
152

153
    public function component(InteractiveConsoleComponent $component, array $validation = []): mixed
36✔
154
    {
155
        if ($this->supportsTty()) {
36✔
UNCOV
156
            return $this->componentRenderer->render($this, $component, $validation);
×
157
        }
158

159
        if ($component instanceof HasStaticComponent) {
36✔
160
            return $component->getStaticComponent()->render($this);
36✔
161
        }
162

UNCOV
163
        throw new UnsupportedComponent($component);
×
164
    }
165

166
    public function ask(
32✔
167
        string $question,
168
        ?array $options = null,
169
        mixed $default = null,
170
        bool $multiple = false,
171
        bool $asList = false,
172
        array $validation = [],
173
    ): null|string|array {
174
        if ($options === null || $options === []) {
32✔
175
            $component = new TextBoxComponent($question, $default);
10✔
176
        } elseif ($multiple) {
25✔
177
            $component = new MultipleChoiceComponent(
8✔
178
                question: $question,
8✔
179
                options: $options,
8✔
180
                default: is_array($default) ? $default : [$default],
8✔
181
            );
8✔
182
        } else {
183
            $component = new SingleChoiceComponent(
22✔
184
                question: $question,
22✔
185
                options: $options,
22✔
186
                default: $default,
22✔
187
                asList: $asList,
22✔
188
            );
22✔
189
        }
190

191
        return $this->component($component, $validation);
32✔
192
    }
193

194
    public function confirm(string $question, bool $default = false): bool
19✔
195
    {
196
        if ($this->isForced) {
19✔
197
            return true;
5✔
198
        }
199

200
        return $this->component(new ConfirmComponent($question, $default));
14✔
201
    }
202

UNCOV
203
    public function password(string $label = 'Password', bool $confirm = false): string
×
204
    {
UNCOV
205
        if (! $confirm) {
×
UNCOV
206
            return $this->component(new PasswordComponent($label));
×
207
        }
208

UNCOV
209
        $password = null;
×
UNCOV
210
        $passwordConfirm = null;
×
211

UNCOV
212
        while ($password === null || $password !== $passwordConfirm) {
×
UNCOV
213
            if ($password !== null) {
×
UNCOV
214
                $this->error("Passwords don't match");
×
215
            }
216

UNCOV
217
            $password = $this->component(new PasswordComponent($label));
×
UNCOV
218
            $passwordConfirm = $this->component(new PasswordComponent('Please confirm'));
×
219
        }
220

UNCOV
221
        return $password;
×
222
    }
223

224
    public function progressBar(iterable $data, Closure $handler): array
1✔
225
    {
226
        return $this->component(new ProgressBarComponent($data, $handler));
1✔
227
    }
228

229
    public function search(string $label, Closure $search, ?string $default = null): mixed
5✔
230
    {
231
        return $this->component(new SearchComponent($label, $search, $default));
5✔
232
    }
233

234
    public function supportsTty(): bool
36✔
235
    {
236
        if ($this->supportsTty === false) {
36✔
UNCOV
237
            return false;
×
238
        }
239

240
        if ($this->componentRenderer === null) {
36✔
241
            return false;
36✔
242
        }
243

UNCOV
244
        if (! $this->supportsPrompting()) {
×
UNCOV
245
            return false;
×
246
        }
247

UNCOV
248
        return (bool) shell_exec('which tput && which stty');
×
249
    }
250

251
    public function supportsPrompting(): bool
35✔
252
    {
253
        if ($this->supportsPrompting === false) {
35✔
254
            return false;
8✔
255
        }
256

257
        if ($this->argumentBag->get('interaction')?->value === false) {
27✔
UNCOV
258
            return false;
×
259
        }
260

261
        return true;
27✔
262
    }
263
}
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

© 2026 Coveralls, Inc