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

tempestphp / tempest-framework / 12021213285

26 Nov 2024 12:18AM UTC coverage: 77.441% (-2.0%) from 79.441%
12021213285

Pull #754

github

web-flow
Merge 46eda39bc into cc0c7eea3
Pull Request #754: feat(framework): overhaul console interactions

734 of 1174 new or added lines in 55 files covered. (62.52%)

54 existing lines in 12 files now uncovered.

8239 of 10639 relevant lines covered (77.44%)

60.83 hits per line

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

90.28
/src/Tempest/Console/src/Components/OptionCollection.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\Console\Components;
6

7
use Countable;
8
use Iterator;
9
use function Tempest\Support\arr;
10
use Tempest\Support\ArrayHelper;
11

12
final class OptionCollection implements Iterator, Countable
13
{
14
    /** @var array<Option> */
15
    private array $options;
16

17
    /** @var array<Option> */
18
    private array $filteredOptions;
19

20
    /** @var array<Option> */
21
    private array $selectedOptions = [];
22

23
    private int $activeOption = 0;
24

25
    private bool $preserveKeys = false;
26

27
    public function __construct(iterable $options)
47✔
28
    {
29
        $this->setCollection($options);
47✔
30
    }
31

32
    public function setCollection(iterable $options): void
47✔
33
    {
34
        $options = arr($options);
47✔
35

36
        $this->preserveKeys = $options->isAssoc();
47✔
37
        $this->options = $options
47✔
38
            ->map(fn (mixed $value, string|int $key) => new Option($key, $value))
47✔
39
            ->toArray();
47✔
40

41
        $this->filter(null);
47✔
42
    }
43

44
    public function filter(?string $query): void
47✔
45
    {
46
        $previouslyActiveOption = $this->getActive();
47✔
47
        $previouslySelectedOptions = $this->selectedOptions;
47✔
48

49
        $this->filteredOptions = arr($this->options)
47✔
50
            ->filter(fn (Option $option) => empty($query) || str_contains(mb_strtolower($option->value), mb_strtolower(trim($query))))
47✔
51
            ->values()
47✔
52
            ->toArray();
47✔
53

54
        $this->selectedOptions = array_filter($this->filteredOptions, fn (Option $option) => in_array($option, $previouslySelectedOptions, strict: true));
47✔
55
        $this->activeOption = array_search($previouslyActiveOption ?? $this->filteredOptions[0] ?? '', $this->filteredOptions, strict: true) ?: 0;
47✔
56
    }
57

58
    public function count(): int
15✔
59
    {
60
        return count($this->filteredOptions);
15✔
61
    }
62

63
    public function previous(): void
1✔
64
    {
65
        $this->activeOption -= 1;
1✔
66

67
        if ($this->activeOption < 0) {
1✔
68
            $this->activeOption = $this->count() - 1;
1✔
69
        }
70
    }
71

72
    public function next(): void
13✔
73
    {
74
        $this->activeOption += 1;
13✔
75

76
        if ($this->activeOption > $this->count() - 1) {
13✔
77
            $this->activeOption = 0;
1✔
78
        }
79
    }
80

81
    public function toggleCurrent(): void
9✔
82
    {
83
        if (($active = $this->getActive()) === null) {
9✔
NEW
84
            return;
×
85
        }
86

87
        if (! $this->isSelected($active)) {
9✔
88
            $this->selectedOptions[] = $active;
9✔
89
        } else {
90
            $this->selectedOptions = array_filter($this->selectedOptions, fn (Option $option) => ! $active->equals($option));
1✔
91
        }
92
    }
93

94
    public function getOptions(): ArrayHelper
2✔
95
    {
96
        return arr($this->filteredOptions)->values();
2✔
97
    }
98

99
    public function getRawOptions(): array
25✔
100
    {
101
        return array_map(static fn (Option $option) => $option->value, $this->options);
25✔
102
    }
103

104
    /** @return array<Option> */
105
    public function getSelectedOptions(): array
3✔
106
    {
107
        return $this->selectedOptions;
3✔
108
    }
109

110
    /** @return array<mixed> */
111
    public function getRawSelectedOptions(): array
9✔
112
    {
113
        $selected = arr($this->selectedOptions)
9✔
114
            ->mapWithKeys(static fn (Option $option) => yield $option->key => $option->value)
9✔
115
            ->toArray();
9✔
116

117
        // TODO: PR `tap` to `ArrayHelper`
118
        if (! $this->preserveKeys) {
9✔
119
            return array_values($selected);
8✔
120
        }
121

122
        return $selected;
1✔
123
    }
124

125
    /** @return array<Option> */
126
    public function getScrollableSection(int $offset = 0, ?int $count = null): array
4✔
127
    {
128
        return array_slice(
4✔
129
            $this->filteredOptions,
4✔
130
            $offset,
4✔
131
            $count,
4✔
132
            preserve_keys: true,
4✔
133
        );
4✔
134
    }
135

136
    public function getCurrentIndex(): int
3✔
137
    {
138
        return array_search($this->activeOption, array_keys($this->filteredOptions), strict: true) ?: 0;
3✔
139
    }
140

141
    public function isSelected(Option $option): bool
12✔
142
    {
143
        return (bool) arr($this->selectedOptions)->first(fn (Option $other) => $option->equals($other));
12✔
144
    }
145

146
    public function isActive(Option $option): bool
3✔
147
    {
148
        return (bool) $this->current()?->equals($option);
3✔
149
    }
150

151
    public function isList(): bool
4✔
152
    {
153
        return array_is_list($this->options);
4✔
154
    }
155

156
    public function getActive(): ?Option
47✔
157
    {
158
        return $this->filteredOptions[$this->activeOption] ?? null;
47✔
159
    }
160

161
    public function current(): ?Option
4✔
162
    {
163
        return $this->getActive();
4✔
164
    }
165

NEW
166
    public function key(): mixed
×
167
    {
NEW
168
        return $this->activeOption;
×
169
    }
170

NEW
171
    public function valid(): bool
×
172
    {
NEW
173
        return isset($this->filteredOptions[$this->activeOption]);
×
174
    }
175

NEW
176
    public function rewind(): void
×
177
    {
NEW
178
        $this->activeOption = 0;
×
179
    }
180
}
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