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

tempestphp / tempest-framework / 14024978163

23 Mar 2025 05:55PM UTC coverage: 79.391% (-0.05%) from 79.441%
14024978163

push

github

web-flow
feat(view): cache Blade and Twig templates in internal storage (#1061)

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

912 existing lines in 110 files now uncovered.

10478 of 13198 relevant lines covered (79.39%)

91.09 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
    ) {
33
    }
2✔
34

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

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

49
            return ExitCode::ERROR;
×
50
        }
51

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

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

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

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

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

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

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

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

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

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

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

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

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

120
        $this->console->writeln();
×
121

122
        return $return;
×
123
    }
124

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

UNCOV
133
            return;
×
134
        }
135

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

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

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

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

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

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

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

172
            return $result;
1✔
173
        }
174

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

179
        return $value;
1✔
180
    }
181

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

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