Issues (536)

src/Cli/Commands/Utilities/About.php (6 issues)

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
     * Elements deja afficher
66
     */
67
    protected static array $displayed = [];
68
69
    /**
70
     * {@inheritDoc}
71
     */
72
    public function execute(array $params)
73
    {
74
        $this->gatherApplicationInformation();
75
76
        $this->center('Information générales sur votre application', ['fg' => Color::YELLOW]);
77
        $this->border();
78
79
        collect(static::$data)
80
            ->map(
81
                static fn ($items) => collect($items)
82
                    ->map(static function ($value) {
83
                        if (is_array($value)) {
84
                            return [$value];
85
                        }
86
87
                        if (is_string($value)) {
88
                            $value = Container::make($value);
89
                        }
90
91
                        return collect(Container::call($value))
92
                            ->map(static fn ($value, $key) => [$key, $value])
93
                            ->values()
94
                            ->all();
95
                    })->flatten(1)
96
            )
97
            ->sortBy(static function ($data, $key): int {
98
                $index = array_search($key, ['Environnement', 'Cache', 'Gestionnaires'], true);
99
100
                return $index === false ? 99 : $index;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $index === false ? 99 : $index could return the type string which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
101
            })
102
            ->filter(fn ($data, $key) => ((bool) $this->option('only')) ? in_array($this->toSearchKeyword($key), $this->sections(), true) : true)
103
            ->pipe(fn ($data) => $this->display($data));
104
105
        return EXIT_SUCCESS;
106
    }
107
108
    /**
109
     * Affiche les informations sur l'application.
110
     */
111
    protected function display(Collection $data): void
112
    {
113
        ((bool) $this->option('json')) ? $this->displayJson($data) : $this->displayDetail($data);
114
    }
115
116
    /**
117
     * Affiche les informations sur l'application sous forme de vue détaillée.
118
     */
119
    protected function displayDetail(Collection $data): void
120
    {
121
        $data->each(function ($data, $section): void {
122
            $this->newLine();
123
124
            $this->justify($section, '', ['first' => ['fg' => Color::GREEN]]);
125
126
            $data->pipe(static fn ($data) => $section !== 'Environnement' ? $data->sort() : $data)->each(function ($detail): void {
127
                [$label, $value] = $detail;
128
                if (! in_array($label, static::$displayed, true)) {
129
                    $this->justify($label, value($value, false));
130
                    static::$displayed[] = $label;
131
                }
132
            });
133
        });
134
    }
135
136
    /**
137
     * Affiche les informations sur l'application sous forme de json.
138
     */
139
    protected function displayJson(Collection $data): void
140
    {
141
        $output = $data->flatMap(fn ($data, $section) => [
142
            (string) Text::of($section)->snake() => $data->mapWithKeys(fn ($item, $key) => [
0 ignored issues
show
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

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

169
            'URL'           => Text::of($config->baseURL)->replace(['http://', 'https://'], /** @scrutinizer ignore-type */ ''),
Loading history...
170
            // 'Maintenance Mode' => static::format($this->laravel->isDownForMaintenance(), console: $formatEnabledStatus),
171
        ]);
172
173
        static::addToSection('Cache', fn () => [
174
            // 'Config' => static::format($this->laravel->configurationIsCached(), console: $formatCachedStatus),
175
            // 'Events' => static::format($this->laravel->eventsAreCached(), console: $formatCachedStatus),
176
            // 'Routes' => static::format($this->laravel->routesAreCached(), console: $formatCachedStatus),
177
            'Vues' => static::format($this->hasPhpFiles(storage_path('framework/cache/views')), console: $formatCachedStatus),
178
        ]);
179
180
        static::addToSection('Gestionnaires', static fn () => array_filter([
181
            'Cache' => config('cache.handler'),
182
            'Logs'  => static function ($json): string {
0 ignored issues
show
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

182
            'Logs'  => static function (/** @scrutinizer ignore-unused */ $json): string {

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...
183
                $handlers = [];
184
185
                foreach (config('log.handlers') as $k => $v) {
186
                    $handlers[] = $k;
187
                }
188
189
                return implode(', ', $handlers);
190
            },
191
            'Mail'    => config('mail.handler'),
192
            'Session' => config('session.handler'),
193
        ]));
194
195
        collect(static::$customDataResolvers)->each->__invoke();
196
    }
197
198
    /**
199
     * Détermine si le répertoire donné contient des fichiers PHP.
200
     */
201
    protected function hasPhpFiles(string $path): bool
202
    {
203
        return count(glob($path . '/*.php')) > 0;
204
    }
205
206
    /**
207
     * Ajoute des données supplémentaires à la sortie de la commande "about".
208
     *
209
     * @param array|callable|string $data
210
     */
211
    public static function add(string $section, $data, ?string $value = null): void
212
    {
213
        static::$customDataResolvers[] = static fn () => static::addToSection($section, $data, $value);
214
    }
215
216
    /**
217
     * Ajoute des données supplémentaires à la sortie de la commande "about".
218
     *
219
     * @param array|callable|string $data
220
     */
221
    protected static function addToSection(string $section, $data, ?string $value = null): void
222
    {
223
        if (is_array($data)) {
224
            foreach ($data as $key => $value) {
225
                self::$data[$section][] = [$key, $value];
226
            }
227
        } elseif (is_callable($data) || ($value === null && class_exists($data))) {
0 ignored issues
show
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

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