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

tempestphp / tempest-framework / 14049246919

24 Mar 2025 09:42PM UTC coverage: 79.353% (-0.04%) from 79.391%
14049246919

push

github

web-flow
feat(support): support array parameters in string manipulations (#1073)

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

735 existing lines in 126 files now uncovered.

10492 of 13222 relevant lines covered (79.35%)

90.78 hits per line

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

67.07
/src/Tempest/Framework/Commands/ConfigShowCommand.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\Framework\Commands;
6

7
use Tempest\Console\ConsoleArgument;
8
use Tempest\Console\ConsoleCommand;
9
use Tempest\Console\ExitCode;
10
use Tempest\Console\HasConsole;
11
use Tempest\Core\Kernel\LoadConfig;
12
use Tempest\Highlight\Languages\Json\JsonLanguage;
13
use Tempest\Highlight\Languages\Php\PhpLanguage;
14
use Tempest\Reflection\ClassReflector;
15

16
use function file_get_contents;
17
use function function_exists;
18
use function is_array;
19
use function is_object;
20
use function realpath;
21
use function str_contains;
22
use function var_export;
23

24
final readonly class ConfigShowCommand
25
{
26
    use HasConsole;
27

28
    private const int MAX_JSON_DEPTH = 32;
29

30
    public function __construct(
2✔
31
        private LoadConfig $loadConfig,
32
    ) {}
2✔
33

34
    #[ConsoleCommand(name: 'config:show', description: 'Shows resolved configuration files', aliases: ['config'])]
2✔
35
    public function __invoke(
36
        #[ConsoleArgument(description: 'Specifies the format in which the configuration should be printed.')]
37
        ConfigShowFormat $format = ConfigShowFormat::PRETTY,
38
        #[ConsoleArgument(description: 'Searches configuration files interactively.')]
39
        ?bool $search = false,
40
        #[ConsoleArgument(description: 'Filters the configuration files by the given string.')]
41
        ?string $filter = null,
42
    ): ExitCode {
43
        $configs = $this->resolveConfig($filter, $search);
2✔
44

45
        if ($configs === []) {
2✔
UNCOV
46
            $this->console->error('No configuration found.');
×
47

UNCOV
48
            return ExitCode::ERROR;
×
49
        }
50

51
        match ($format) {
52
            ConfigShowFormat::DUMP => $this->dump($configs),
2✔
53
            ConfigShowFormat::PRETTY => $this->pretty($configs),
2✔
54
            ConfigShowFormat::FILE => $this->file($configs),
1✔
55
        };
56

57
        return ExitCode::SUCCESS;
2✔
58
    }
59

60
    /**
61
     * @return array<string, mixed>
62
     */
63
    private function resolveConfig(?string $filter, bool $search): array
2✔
64
    {
65
        $configPaths = $this->loadConfig->find();
2✔
66
        $configs = [];
2✔
67
        $uniqueMap = [];
2✔
68

69
        foreach ($configPaths as $configPath) {
2✔
70
            $config = require $configPath;
2✔
71
            $configPath = realpath($configPath);
2✔
72

73
            if ($filter === null || str_contains($configPath, $filter) || str_contains($config::class, $filter)) {
2✔
74
                $configs[$configPath] = $config;
2✔
75
                $uniqueMap[$config::class] = $configPath;
2✔
76
            }
77
        }
78

79
        // LoadConfig::find() returns all config paths
80
        // that are overwritten by container in their order
81
        $resolvedConfigs = [];
2✔
82

83
        foreach ($uniqueMap as $configPath) {
2✔
84
            $resolvedConfigs[$configPath] = $configs[$configPath];
2✔
85
        }
86

87
        if (! $search) {
2✔
88
            return $resolvedConfigs;
2✔
89
        }
90

UNCOV
91
        $selectedPath = $this->searchConfigFile($resolvedConfigs);
×
92

UNCOV
93
        return [$selectedPath => $resolvedConfigs[$selectedPath]];
×
94
    }
95

96
    /**
97
     * @param array<string, mixed> $configs
98
     */
UNCOV
99
    private function searchConfigFile(array $configs): string
×
100
    {
UNCOV
101
        $data = array_keys($configs);
×
102
        sort($data);
×
103

UNCOV
104
        $return = $this->console->search(
×
105
            label: 'Which configuration file would you like to view?',
×
106
            search: function (string $query) use ($data): array {
×
107
                if ($query === '') {
×
108
                    return $data;
×
109
                }
110

UNCOV
111
                return array_filter(
×
112
                    array: $data,
×
113
                    callback: fn (string $path) => str_contains($path, $query),
×
114
                );
×
115
            },
×
116
            default: $data[0],
×
117
        );
×
118

UNCOV
119
        $this->console->writeln();
×
120

UNCOV
121
        return $return;
×
122
    }
123

124
    /**
125
     * @param array<string, mixed> $configs
126
     */
UNCOV
127
    private function dump(array $configs): void
×
128
    {
UNCOV
129
        if (function_exists('lw')) {
×
130
            lw($configs);
×
131

UNCOV
132
            return;
×
133
        }
134

UNCOV
135
        $this->console->writeln(var_export($configs, true)); // @mago-expect best-practices/no-debug-symbols
×
136
    }
137

138
    /**
139
     * @param array<string, mixed> $configs
140
     */
141
    private function pretty(array $configs): void
1✔
142
    {
143
        $formatted = $this->formatForJson($configs);
1✔
144

145
        $this->console->writeWithLanguage(
1✔
146
            json_encode(
1✔
147
                $formatted,
1✔
148
                JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE,
1✔
149
            ),
1✔
150
            new JsonLanguage(),
1✔
151
        );
1✔
152
    }
153

154
    private function formatForJson(mixed $value, int $depth = 0): mixed
1✔
155
    {
156
        if ($depth > self::MAX_JSON_DEPTH) {
1✔
UNCOV
157
            return '@...';
×
158
        }
159

160
        if (is_object($value)) {
1✔
161
            $result = [
1✔
162
                '@type' => $value::class,
1✔
163
            ];
1✔
164

165
            $reflector = new ClassReflector($value);
1✔
166

167
            foreach ($reflector->getProperties() as $property) {
1✔
168
                $result[$property->getName()] = $this->formatForJson($property->getValue($value), $depth + 1);
1✔
169
            }
170

171
            return $result;
1✔
172
        }
173

174
        if (is_array($value)) {
1✔
175
            return array_map(fn ($item) => $this->formatForJson($item, $depth + 1), $value);
1✔
176
        }
177

178
        return $value;
1✔
179
    }
180

181
    /**
182
     * @param array<string, mixed> $configs
183
     */
184
    private function file(array $configs): void
1✔
185
    {
186
        $phpLanguage = new PhpLanguage();
1✔
187

188
        foreach (array_keys($configs) as $path) {
1✔
189
            $this->console->writeln("<em>{$path}</em>");
1✔
190
            $this->console->writeWithLanguage(
1✔
191
                file_get_contents($path),
1✔
192
                $phpLanguage,
1✔
193
            );
1✔
194
            $this->console->writeln();
1✔
195
        }
196
    }
197
}
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