Passed
Push — main ( 93c2a6...737a66 )
by Dimitri
03:08
created

About::displayDetail()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 11
ccs 0
cts 4
cp 0
crap 6
rs 10
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\Cli\Commands\Utilities;
13
14
use Ahc\Cli\Output\Color;
15
use BlitzPHP\Cli\Console\Command;
16
use BlitzPHP\Debug\Toolbar\Collectors\Config;
17
use BlitzPHP\Facades\Container;
18
use BlitzPHP\Utilities\Iterable\Collection;
19
use BlitzPHP\Utilities\String\Text;
20
use Closure;
21
22
/**
23
 * Affiche les informations de base sur de l'application
24
 */
25
class About extends Command
26
{
27
    /**
28
     * @var string Groupe
29
     */
30
    protected $group = 'BlitzPHP';
31
32
    protected $service = 'Service de configuration';
33
34
    /**
35
     * @var string Nom
36
     */
37
    protected $name = 'about';
38
39
    /**
40
     * @var string Description
41
     */
42
    protected $description = 'Affiche les informations de base sur de l\'application.';
43
44
    /**
45
     * Options de la commande
46
     *
47
     * @var array<string, string>
48
     */
49
    protected $options = [
50
        '--only' => 'La section à afficher.',
51
        '--json' => 'Afficher les informations au format json.',
52
    ];
53
54
    /**
55
     * Donnees a afficher.
56
     */
57
    protected static array $data = [];
58
59
    /**
60
     * Les callables enregistrés qui ajoutent des données personnalisées à la sortie de la commande.
61
     */
62
    protected static array $customDataResolvers = [];
63
64
    /**
65
     * {@inheritDoc}
66
     */
67
    public function execute(array $params)
68
    {
69
        $this->gatherApplicationInformation();
70
71
        $this->center('Information générales sur votre application', ['fg' => Color::YELLOW]);
72
        $this->border();
73
74
75
        collect(static::$data)
76
            ->map(fn ($items) => collect($items)
77
                ->map(function ($value) {
78
                    if (is_array($value)) {
79
                        return [$value];
80
                    }
81
82
                    if (is_string($value)) {
83
                        $value = Container::make($value);
84
                    }
85
86
                    return collect(Container::call($value))
87
                        ->map(fn ($value, $key) => [$key, $value])
88
                        ->values()
89
                        ->all();
90
                })->flatten(1)
91
            )
92
            ->sortBy(function ($data, $key) {
93
                $index = array_search($key, ['Environnement', 'Cache', 'Gestionnaires']);
94
95
                return $index === false ? 99 : $index;
96
            })
97
            ->filter(function ($data, $key) {
98
                return $this->option('only') ? in_array($this->toSearchKeyword($key), $this->sections()) : true;
99
            })
100
            ->pipe(fn ($data) => $this->display($data));
101
102
103
        return EXIT_SUCCESS;
104
    }
105
    
106
    /**
107
     * Affiche les informations sur l'application.
108
     */
109
    protected function display(Collection $data): void
110
    {
111
        $this->option('json') ? $this->displayJson($data) : $this->displayDetail($data);
112
    }
113
114
    /**
115
     * Affiche les informations sur l'application sous forme de vue détaillée.
116
     */
117
    protected function displayDetail(Collection $data): void
118
    {
119
        $data->each(function ($data, $section) {
120
            $this->newLine();
121
122
            $this->justify($section, '', ['first' => ['fg' => Color::GREEN]]);
123
 
124
            $data->pipe(fn ($data) => $section !== 'Environnement' ? $data->sort() : $data)->each(function ($detail) {
125
                [$label, $value] = $detail;
126
127
                $this->justify($label, value($value, false));
128
            });
129
        });
130
    }
131
132
    /**
133
     * Affiche les informations sur l'application sous forme de json.
134
     */
135
    protected function displayJson(Collection $data): void
136
    {
137
        $output = $data->flatMap(function ($data, $section) {
138
            return [
139
                (string) Text::of($section)->snake() => $data->mapWithKeys(fn ($item, $key) => [
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

139
                (string) Text::of($section)->snake() => $data->mapWithKeys(fn ($item, /** @scrutinizer ignore-unused */ $key) => [

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
140
                    $this->toSearchKeyword($item[0]) => value($item[1], true),
141
                ]),
142
            ];
143
        });
144
145
        $this->eol()->json($output);
146
    }
147
148
    /**
149
     * Rassemble des informations sur l’application.
150
     */
151
    protected function gatherApplicationInformation(): void
152
    {
153
        self::$data = [];
154
155
        $formatEnabledStatus = fn ($value) => $value ? $this->color->warn('ACTIVE') : $this->color->warn('DESACTIVE');
156
        $formatCachedStatus  = fn ($value) => $value ? $this->color->ok('MISE EN CACHE') : $this->color->warn('NON MISE EN CACHE');
157
158
        $config = (object) Config::display();
159
160
        static::addToSection('Environnement', fn () => [
161
            'Nom de l\'application' => $config->appName,
162
            'Version de BlitzPHP' => $config->blitzVersion,
163
            'Version de PHP'      => PHP_VERSION,
164
            // 'Composer Version' => $this->composer->getVersion() ?? '<fg=yellow;options=bold>-</>',
165
            'Environnement'      => $config->environment,
166
            'Mode debug'       => static::format(config('app.debug'), console: $formatEnabledStatus),
167
            'URL'              => Text::of($config->baseURL)->replace(['http://', 'https://'], ''),
0 ignored issues
show
Bug introduced by
'' of type string is incompatible with the type iterable expected by parameter $replace of BlitzPHP\Utilities\String\Stringable::replace(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
            'URL'              => Text::of($config->baseURL)->replace(['http://', 'https://'], /** @scrutinizer ignore-type */ ''),
Loading history...
168
            // 'Maintenance Mode' => static::format($this->laravel->isDownForMaintenance(), console: $formatEnabledStatus),
169
        ]);
170
171
        static::addToSection('Cache', fn () => [
172
            // 'Config' => static::format($this->laravel->configurationIsCached(), console: $formatCachedStatus),
173
            // 'Events' => static::format($this->laravel->eventsAreCached(), console: $formatCachedStatus),
174
            // 'Routes' => static::format($this->laravel->routesAreCached(), console: $formatCachedStatus),
175
            'Vues' => static::format($this->hasPhpFiles(storage_path('framework/cache/views')), console: $formatCachedStatus),
176
        ]);
177
178
        static::addToSection('Gestionnaires', fn () => array_filter([
179
            'Cache'    => config('cache.handler'),
180
            'Base de données' => config('database.default'),
181
            'Logs'     => function ($json) {
0 ignored issues
show
Unused Code introduced by
The parameter $json is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

181
            'Logs'     => function (/** @scrutinizer ignore-unused */ $json) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
182
                $handlers = [];
183
                foreach (config('log.handlers') as $k => $v) {
184
                    $handlers[] = $k;
185
                }
186
187
                return implode(', ', $handlers);
188
            },
189
            'Mail'    => config('mail.handler'),
190
            'Session' => config('session.handler'),
191
        ]));
192
193
        collect(static::$customDataResolvers)->each->__invoke();
194
    }
195
196
    /**
197
     * Détermine si le répertoire donné contient des fichiers PHP.
198
     */
199
    protected function hasPhpFiles(string $path): bool
200
    {
201
        return count(glob($path.'/*.php')) > 0;
202
    }
203
204
    /**
205
     * Ajoute des données supplémentaires à la sortie de la commande "about".
206
     *
207
     * @param  callable|string|array  $data
208
     */
209
    public static function add(string $section, $data, ?string $value = null): void
210
    {
211
        static::$customDataResolvers[] = fn () => static::addToSection($section, $data, $value);
212
    }
213
214
    /**
215
     * Ajoute des données supplémentaires à la sortie de la commande "about".
216
     * 
217
     * @param  callable|string|array  $data
218
     */
219
    protected static function addToSection(string $section, $data, ?string $value = null): void
220
    {
221
        if (is_array($data)) {
222
            foreach ($data as $key => $value) {
223
                self::$data[$section][] = [$key, $value];
224
            }
225
        } elseif (is_callable($data) || ($value === null && class_exists($data))) {
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type callable; however, parameter $class of class_exists() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

225
        } elseif (is_callable($data) || ($value === null && class_exists(/** @scrutinizer ignore-type */ $data))) {
Loading history...
226
            self::$data[$section][] = $data;
227
        } else {
228
            self::$data[$section][] = [$data, $value];
229
        }
230
    }
231
232
    /**
233
     * Récupère les sections fournies à la commande.
234
     */
235
    protected function sections(): array
236
    {
237
        return collect(explode(',', $this->option('only') ?? ''))
238
            ->filter()
239
            ->map(fn ($only) => $this->toSearchKeyword($only))
240
            ->all();
241
    }
242
243
    /**
244
     * Matérialise une fonction qui formate une valeur donnée pour la sortie CLI ou JSON.
245
     *
246
     * @param  (\Closure(mixed):(mixed))|null  $console
0 ignored issues
show
Documentation Bug introduced by
The doc comment (\Closure(mixed):(mixed))|null at position 1 could not be parsed: Expected ')' at position 1, but found '\Closure'.
Loading history...
247
     * @param  (\Closure(mixed):(mixed))|null  $json
248
     * @return \Closure(bool):mixed
249
     */
250
    public static function format(mixed $value, Closure $console = null, Closure $json = null)
251
    {
252
        return function ($isJson) use ($value, $console, $json) {
253
            if ($isJson === true && $json instanceof Closure) {
254
                return value($json, $value);
255
            } elseif ($isJson === false && $console instanceof Closure) {
256
                return value($console, $value);
257
            }
258
259
            return value($value);
260
        };
261
    }
262
263
    /**
264
     * Formatez la chaîne donnée pour la recherche.
265
     */
266
    protected function toSearchKeyword(string $value): string
267
    {
268
        return (string) Text::of($value)->lower()->snake();
269
    }
270
271
    /**
272
     * Videz les données enregistrées.
273
     */
274
    public static function flushState(): void
275
    {
276
        static::$data = [];
277
278
        static::$customDataResolvers = [];
279
    }
280
}
281