Passed
Push — next ( 381d12...e3594a )
by Bas
05:57
created

ShowCommand::handle()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 37
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 2.0002

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 22
nc 2
nop 1
dl 0
loc 37
ccs 23
cts 24
cp 0.9583
crap 2.0002
rs 9.568
c 1
b 0
f 0
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent\Console;
4
5
use ArangoClient\Exceptions\ArangoException;
6
use Illuminate\Database\ConnectionInterface;
7
use Illuminate\Database\ConnectionResolverInterface;
8
use Illuminate\Database\Console\ShowCommand as IlluminateShowCommand;
9
use Illuminate\Database\Schema\Builder as IlluminateSchemaBuilder;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Number;
12
use LaravelFreelancerNL\Aranguent\Connection;
13
use LaravelFreelancerNL\Aranguent\Schema\Builder as SchemaBuilder;
14
15
class ShowCommand extends IlluminateShowCommand
16
{
17
    /**
18
     * The name and signature of the console command.
19
     *
20
     * @var string
21
     */
22
    protected $signature = 'db:show {--database= : The database connection}
23
                {--json : Output the database information as JSON}
24
                {--counts : Show the table row count }
25
                {--views : Show the database views }
26
                {--analyzers : Show the database analyzers (ArangoDB)}
27
                {--graphs : Show the database named graphs (ArangoDB)}
28
                {--system : Show the database system tables (ArangoDB)}
29
                {--types : Show the user defined types (Postgresql)}
30
                {--all : Show tables, analyzers, graphs and views (ArangoDB)}';
31
32
    /**
33
     * The console command description.
34
     *
35
     * @var string
36
     */
37
    protected $description = 'Display information about the given database';
38
39
    /**
40
     * Execute the console command.
41
     *
42
     * @param  \Illuminate\Database\ConnectionResolverInterface  $connections
43
     * @return int
44
     */
45 6
    public function handle(ConnectionResolverInterface $connections)
46
    {
47 6
        $connection = $connections->connection($database = $this->input->getOption('database'));
48
49
        assert($connection instanceof Connection);
50
51 6
        if ($connection->getDriverName() !== 'arangodb') {
52
            return parent::handle($connections);
53
        }
54
55 6
        $schema = $connection->getSchemaBuilder();
56
57 6
        $fullVersion = $this->getFullVersion($connection);
58
59 6
        $data = [
60 6
            'platform' => [
61 6
                'config' => $this->getConfigFromDatabase($database),
62 6
                'server' => $fullVersion->server ?? 'arango',
63 6
                'license' => $fullVersion->license ?? 'unknown',
64 6
                'name' => $connection->getDriverTitle(),
65 6
                'connection' => $connection->getName(),
66 6
                'version' => $fullVersion->version ?? 'unknown',
67 6
                'isSystemDatabase' =>  $this->getDatabaseInfo($connection),
68 6
                'open_connections' => $connection->threadCount(),
69 6
            ],
70 6
            'tables' => $this->tables($connection, $schema),
71 6
        ];
72
73 6
        $data['views'] = $this->views($connection, $schema);
74
75 6
        $data['analyzers'] = $this->analyzers($schema);
76
77 6
        $data['graphs'] = $this->graphs($schema);
78
79 6
        $this->display($data, $connection);
80
81 6
        return 0;
82
    }
83
84
    /**
85
     * Render the database information.
86
     *
87
     * @param array<mixed> $data
88
     * @param Connection|null $connection
89
     * @return void
90
     */
91 6
    protected function display(array $data, ?Connection $connection = null)
92
    {
93 6
        $this->option('json') ? $this->displayJson($data) : $this->displayForCli($data, $connection);
94
    }
95
96
97
    /**
98
     * Get information regarding the tables within the database.
99
     *
100
     * @param  \Illuminate\Database\ConnectionInterface  $connection
101
     * @param  IlluminateSchemaBuilder $schema
102
     * @return \Illuminate\Support\Collection
103
     */
104 6
    protected function tables(ConnectionInterface $connection, $schema)
105
    {
106
        assert($connection instanceof Connection);
107
108 6
        if ($connection->getDriverName() !== 'arangodb') {
109
            return parent::tables($connection, $schema);
110
        }
111
112
        assert($schema instanceof SchemaBuilder);
113
114
        // Get all tables
115 6
        $tables = collect(
116 6
            ($this->input->getOption('system')) ? $schema->getAllTables() : $schema->getTables(),
0 ignored issues
show
Bug introduced by
$this->input->getOption(... : $schema->getTables() of type array|array<mixed,mixed> is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

116
            /** @scrutinizer ignore-type */ ($this->input->getOption('system')) ? $schema->getAllTables() : $schema->getTables(),
Loading history...
117 6
        )->sortBy('name');
118
119
        // Get per table statistics
120 6
        $tableStats = [];
121 6
        foreach ($tables as $table) {
122 6
            $tableStats[] = $schema->getTable($table->name);
123
        }
124
125 6
        return collect($tableStats)->map(fn($table) => [
126 6
            'table' => $table['name'],
127 6
            'size' => $table['figures']->documentsSize,
128 6
            'rows' => $this->option('counts')
129 1
                ? $table['count']
130
                : null,
131 6
        ]);
132
    }
133
134
    /**
135
     * Get information regarding the views within the database.
136
     *
137
     * @param  \Illuminate\Database\ConnectionInterface  $connection
138
     * @param  \Illuminate\Database\Schema\Builder  $schema
139
     * @return \Illuminate\Support\Collection
140
     */
141 6
    protected function views(ConnectionInterface $connection, IlluminateSchemaBuilder $schema)
142
    {
143
        assert($connection instanceof Connection);
144
145 6
        if ($connection->getDriverName() !== 'arangodb') {
146
            return parent::views($connection, $schema);
147
        }
148
149 6
        return collect($schema->getViews())
0 ignored issues
show
Bug introduced by
$schema->getViews() of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

149
        return collect(/** @scrutinizer ignore-type */ $schema->getViews())
Loading history...
150 6
            ->map(fn($view) => [
151 6
                'name' => $view->name,
152 6
                'type' => $view->type,
153 6
            ]);
154
    }
155
156
    /**
157
     * Get information regarding the analyzers within the database.
158
     *
159
     * @param  SchemaBuilder $schema
160
     * @return \Illuminate\Support\Collection
161
     */
162 6
    protected function analyzers(SchemaBuilder $schema)
163
    {
164 6
        return collect($schema->getAnalyzers())
0 ignored issues
show
Bug introduced by
$schema->getAnalyzers() of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

164
        return collect(/** @scrutinizer ignore-type */ $schema->getAnalyzers())
Loading history...
165 6
            ->map(fn($analyzer) => [
166 6
                'name' => $analyzer->name,
167 6
                'type' => $analyzer->type,
168 6
            ]);
169
    }
170
171
    /**
172
     * Get information regarding the named graphs within the database.
173
     *
174
     * @param SchemaBuilder $schema
175
     * @return \Illuminate\Support\Collection
176
     */
177 6
    protected function graphs(SchemaBuilder $schema)
178
    {
179 6
        return collect($schema->getGraphs())
0 ignored issues
show
Bug introduced by
$schema->getGraphs() of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

179
        return collect(/** @scrutinizer ignore-type */ $schema->getGraphs())
Loading history...
180 6
            ->map(fn($graph) => [
181 6
                'name' => $graph->name,
182 6
                'edgeDefinitions' => count($graph->edgeDefinitions),
183 6
            ]);
184
    }
185
186 6
    protected function getFullVersion(Connection $connection): object
187
    {
188 6
        $client = $connection->getArangoClient();
189
190
        assert($client !== null);
191
192 6
        return $client->admin()->getVersion();
193
    }
194
195
    /**
196
     * @throws ArangoException
197
     */
198 6
    protected function getDatabaseInfo(Connection $connection): bool
199
    {
200 6
        $client = $connection->getArangoClient();
201
202
        assert($client !== null);
203
204 6
        $info = $client->schema()->getCurrentDatabase();
205
206 6
        return $info->isSystem;
207
    }
208
209
    /**
210
     * @param mixed $views
211
     * @return void
212
     */
213 6
    public function displayViews(mixed $views): void
214
    {
215 6
        if (! $this->input->getOption('views') || $views->isEmpty()) {
216 5
            return;
217
        }
218
219 1
        $this->components->twoColumnDetail(
220 1
            '<fg=green;options=bold>View</>',
221 1
            '<fg=green;options=bold>Type</>',
222 1
        );
223
224 1
        $views->each(fn($view) => $this->components->twoColumnDetail(
225 1
            $view['name'],
226 1
            $view['type'],
227 1
        ));
228
229 1
        $this->newLine();
230
    }
231
232
    /**
233
     * @param mixed $analyzers
234
     * @return void
235
     */
236 6
    public function displayAnalyzers(mixed $analyzers): void
237
    {
238 6
        if (! $this->input->getOption('analyzers') || $analyzers->isEmpty()) {
239 5
            return;
240
        }
241
242 1
        $this->components->twoColumnDetail(
243 1
            '<fg=green;options=bold>Analyzers</>',
244 1
            '<fg=green;options=bold>Type</>',
245 1
        );
246
247 1
        $analyzers->each(fn($analyzer) => $this->components->twoColumnDetail(
248 1
            $analyzer['name'],
249 1
            $analyzer['type'],
250 1
        ));
251
252 1
        $this->newLine();
253
    }
254
    /**
255
     * @param mixed $graphs
256
     * @return void
257
     */
258 6
    public function displayGraphs(mixed $graphs): void
259
    {
260 6
        if (! $this->input->getOption('graphs') || $graphs->isEmpty()) {
261 5
            return;
262
        }
263
264 1
        $this->components->twoColumnDetail(
265 1
            '<fg=green;options=bold>Graphs</>',
266 1
            '<fg=green;options=bold>Edge Definitions</>',
267 1
        );
268
269 1
        $graphs->each(fn($graph) => $this->components->twoColumnDetail(
270 1
            $graph['name'],
271 1
            $graph['edgeDefinitions'],
272 1
        ));
273
274 1
        $this->newLine();
275
    }
276
277
    /**
278
     * Render the database information formatted for the CLI.
279
     *
280
     * @param array<mixed> $data
281
     * @param Connection|null $connection
282
     * @return void
283
     */
284 6
    protected function displayForCli(array $data, ?Connection $connection = null)
285
    {
286 6
        if ($connection && $connection->getDriverName() !== 'arangodb') {
287
            parent::displayForCli($data);
288
            return;
289
        }
290
291 6
        $platform = $data['platform'];
292 6
        $tables = $data['tables'];
293 6
        $analyzers = $data['analyzers'] ?? null;
294 6
        $views = $data['views'] ?? null;
295 6
        $graphs = $data['graphs'] ?? null;
296
297 6
        $this->newLine();
298
299 6
        $this->components->twoColumnDetail('<fg=green;options=bold>ArangoDB (' . ucfirst($platform['license']) . ' Edition)</>', '<fg=green;options=bold>' . $platform['version'] . '</>');
300 6
        $this->components->twoColumnDetail('Connection', $platform['connection']);
301 6
        $this->components->twoColumnDetail('Database', Arr::get($platform['config'], 'database'));
302 6
        $this->components->twoColumnDetail('Host', Arr::get($platform['config'], 'host'));
303 6
        $this->components->twoColumnDetail('Port', Arr::get($platform['config'], 'port'));
304 6
        $this->components->twoColumnDetail('Username', Arr::get($platform['config'], 'username'));
305 6
        $this->components->twoColumnDetail('URL', Arr::get($platform['config'], 'url') ?? Arr::get($platform['config'], 'endpoint'));
306 6
        $this->components->twoColumnDetail('Open Connections', $platform['open_connections']);
307 6
        $this->components->twoColumnDetail('Analyzers', $analyzers->count());
0 ignored issues
show
Bug introduced by
The method count() does not exist on null. ( Ignorable by Annotation )

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

307
        $this->components->twoColumnDetail('Analyzers', $analyzers->/** @scrutinizer ignore-call */ count());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
308 6
        $this->components->twoColumnDetail('Views', $views->count());
0 ignored issues
show
Bug introduced by
The method count() does not exist on null. ( Ignorable by Annotation )

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

308
        $this->components->twoColumnDetail('Views', $views->/** @scrutinizer ignore-call */ count());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
309 6
        $this->components->twoColumnDetail('Named Graphs', $graphs->count());
0 ignored issues
show
Bug introduced by
The method count() does not exist on null. ( Ignorable by Annotation )

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

309
        $this->components->twoColumnDetail('Named Graphs', $graphs->/** @scrutinizer ignore-call */ count());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
310 6
        $this->components->twoColumnDetail('Tables', $tables->count());
311
312 6
        $tableSizeSum = $tables->sum('size');
313 6
        if ($tableSizeSum) {
314 6
            $this->components->twoColumnDetail('Total Size Estimate', Number::fileSize($tableSizeSum, 2));
315
        }
316
317 6
        $this->newLine();
318
319 6
        if ($tables->isNotEmpty()) {
320 6
            $this->components->twoColumnDetail(
321 6
                '<fg=green;options=bold>Table</>',
322 6
                'Size Estimate' . ($this->option('counts') ? ' <fg=gray;options=bold>/</> <fg=yellow;options=bold>Rows</>' : ''),
323 6
            );
324
325 6
            $tables->each(function ($table) {
326 6
                $tableSize = is_null($table['size']) ? null : Number::fileSize($table['size'], 2);
327
328 6
                $this->components->twoColumnDetail(
329 6
                    $table["table"],
330 6
                    ($tableSize ?? '—') . ($this->option('counts') ? ' <fg=gray;options=bold>/</> <fg=yellow;options=bold>' . Number::format($table['rows']) . '</>' : ''),
331 6
                );
332 6
            });
333
334 6
            $this->newLine();
335
        }
336
337 6
        $this->displayViews($views);
338
339 6
        $this->displayAnalyzers($analyzers);
340
341 6
        $this->displayGraphs($graphs);
342
    }
343
}
344