ShowCommand.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <?php
  2. namespace Illuminate\Database\Console;
  3. use Illuminate\Database\ConnectionInterface;
  4. use Illuminate\Database\ConnectionResolverInterface;
  5. use Illuminate\Database\Schema\Builder;
  6. use Illuminate\Support\Arr;
  7. use Illuminate\Support\Number;
  8. use Symfony\Component\Console\Attribute\AsCommand;
  9. #[AsCommand(name: 'db:show')]
  10. class ShowCommand extends DatabaseInspectionCommand
  11. {
  12. /**
  13. * The name and signature of the console command.
  14. *
  15. * @var string
  16. */
  17. protected $signature = 'db:show {--database= : The database connection}
  18. {--json : Output the database information as JSON}
  19. {--counts : Show the table row count <bg=red;options=bold> Note: This can be slow on large databases </>}
  20. {--views : Show the database views <bg=red;options=bold> Note: This can be slow on large databases </>}
  21. {--types : Show the user defined types}';
  22. /**
  23. * The console command description.
  24. *
  25. * @var string
  26. */
  27. protected $description = 'Display information about the given database';
  28. /**
  29. * Execute the console command.
  30. *
  31. * @param \Illuminate\Database\ConnectionResolverInterface $connections
  32. * @return int
  33. */
  34. public function handle(ConnectionResolverInterface $connections)
  35. {
  36. $connection = $connections->connection($database = $this->input->getOption('database'));
  37. $schema = $connection->getSchemaBuilder();
  38. $data = [
  39. 'platform' => [
  40. 'config' => $this->getConfigFromDatabase($database),
  41. 'name' => $this->getConnectionName($connection, $database),
  42. 'version' => $connection->getServerVersion(),
  43. 'open_connections' => $this->getConnectionCount($connection),
  44. ],
  45. 'tables' => $this->tables($connection, $schema),
  46. ];
  47. if ($this->option('views')) {
  48. $data['views'] = $this->views($connection, $schema);
  49. }
  50. if ($this->option('types')) {
  51. $data['types'] = $this->types($connection, $schema);
  52. }
  53. $this->display($data);
  54. return 0;
  55. }
  56. /**
  57. * Get information regarding the tables within the database.
  58. *
  59. * @param \Illuminate\Database\ConnectionInterface $connection
  60. * @param \Illuminate\Database\Schema\Builder $schema
  61. * @return \Illuminate\Support\Collection
  62. */
  63. protected function tables(ConnectionInterface $connection, Builder $schema)
  64. {
  65. return collect($schema->getTables())->map(fn ($table) => [
  66. 'table' => $table['name'],
  67. 'schema' => $table['schema'],
  68. 'size' => $table['size'],
  69. 'rows' => $this->option('counts') ? $connection->table($table['name'])->count() : null,
  70. 'engine' => $table['engine'],
  71. 'collation' => $table['collation'],
  72. 'comment' => $table['comment'],
  73. ]);
  74. }
  75. /**
  76. * Get information regarding the views within the database.
  77. *
  78. * @param \Illuminate\Database\ConnectionInterface $connection
  79. * @param \Illuminate\Database\Schema\Builder $schema
  80. * @return \Illuminate\Support\Collection
  81. */
  82. protected function views(ConnectionInterface $connection, Builder $schema)
  83. {
  84. return collect($schema->getViews())
  85. ->reject(fn ($view) => str($view['name'])->startsWith(['pg_catalog', 'information_schema', 'spt_']))
  86. ->map(fn ($view) => [
  87. 'view' => $view['name'],
  88. 'schema' => $view['schema'],
  89. 'rows' => $connection->table($view->getName())->count(),
  90. ]);
  91. }
  92. /**
  93. * Get information regarding the user-defined types within the database.
  94. *
  95. * @param \Illuminate\Database\ConnectionInterface $connection
  96. * @param \Illuminate\Database\Schema\Builder $schema
  97. * @return \Illuminate\Support\Collection
  98. */
  99. protected function types(ConnectionInterface $connection, Builder $schema)
  100. {
  101. return collect($schema->getTypes())
  102. ->map(fn ($type) => [
  103. 'name' => $type['name'],
  104. 'schema' => $type['schema'],
  105. 'type' => $type['type'],
  106. 'category' => $type['category'],
  107. ]);
  108. }
  109. /**
  110. * Render the database information.
  111. *
  112. * @param array $data
  113. * @return void
  114. */
  115. protected function display(array $data)
  116. {
  117. $this->option('json') ? $this->displayJson($data) : $this->displayForCli($data);
  118. }
  119. /**
  120. * Render the database information as JSON.
  121. *
  122. * @param array $data
  123. * @return void
  124. */
  125. protected function displayJson(array $data)
  126. {
  127. $this->output->writeln(json_encode($data));
  128. }
  129. /**
  130. * Render the database information formatted for the CLI.
  131. *
  132. * @param array $data
  133. * @return void
  134. */
  135. protected function displayForCli(array $data)
  136. {
  137. $platform = $data['platform'];
  138. $tables = $data['tables'];
  139. $views = $data['views'] ?? null;
  140. $types = $data['types'] ?? null;
  141. $this->newLine();
  142. $this->components->twoColumnDetail('<fg=green;options=bold>'.$platform['name'].'</>', $platform['version']);
  143. $this->components->twoColumnDetail('Database', Arr::get($platform['config'], 'database'));
  144. $this->components->twoColumnDetail('Host', Arr::get($platform['config'], 'host'));
  145. $this->components->twoColumnDetail('Port', Arr::get($platform['config'], 'port'));
  146. $this->components->twoColumnDetail('Username', Arr::get($platform['config'], 'username'));
  147. $this->components->twoColumnDetail('URL', Arr::get($platform['config'], 'url'));
  148. $this->components->twoColumnDetail('Open Connections', $platform['open_connections']);
  149. $this->components->twoColumnDetail('Tables', $tables->count());
  150. if ($tableSizeSum = $tables->sum('size')) {
  151. $this->components->twoColumnDetail('Total Size', Number::fileSize($tableSizeSum, 2));
  152. }
  153. $this->newLine();
  154. if ($tables->isNotEmpty()) {
  155. $hasSchema = ! is_null($tables->first()['schema']);
  156. $this->components->twoColumnDetail(
  157. ($hasSchema ? '<fg=green;options=bold>Schema</> <fg=gray;options=bold>/</> ' : '').'<fg=green;options=bold>Table</>',
  158. 'Size'.($this->option('counts') ? ' <fg=gray;options=bold>/</> <fg=yellow;options=bold>Rows</>' : '')
  159. );
  160. $tables->each(function ($table) {
  161. if ($tableSize = $table['size']) {
  162. $tableSize = Number::fileSize($tableSize, 2);
  163. }
  164. $this->components->twoColumnDetail(
  165. ($table['schema'] ? $table['schema'].' <fg=gray;options=bold>/</> ' : '').$table['table'].($this->output->isVerbose() ? ' <fg=gray>'.$table['engine'].'</>' : null),
  166. ($tableSize ?: '—').($this->option('counts') ? ' <fg=gray;options=bold>/</> <fg=yellow;options=bold>'.Number::format($table['rows']).'</>' : '')
  167. );
  168. if ($this->output->isVerbose()) {
  169. if ($table['comment']) {
  170. $this->components->bulletList([
  171. $table['comment'],
  172. ]);
  173. }
  174. }
  175. });
  176. $this->newLine();
  177. }
  178. if ($views && $views->isNotEmpty()) {
  179. $hasSchema = ! is_null($views->first()['schema']);
  180. $this->components->twoColumnDetail(
  181. ($hasSchema ? '<fg=green;options=bold>Schema</> <fg=gray;options=bold>/</> ' : '').'<fg=green;options=bold>View</>',
  182. '<fg=green;options=bold>Rows</>'
  183. );
  184. $views->each(fn ($view) => $this->components->twoColumnDetail(
  185. ($view['schema'] ? $view['schema'].' <fg=gray;options=bold>/</> ' : '').$view['view'],
  186. Number::format($view['rows'])
  187. ));
  188. $this->newLine();
  189. }
  190. if ($types && $types->isNotEmpty()) {
  191. $hasSchema = ! is_null($types->first()['schema']);
  192. $this->components->twoColumnDetail(
  193. ($hasSchema ? '<fg=green;options=bold>Schema</> <fg=gray;options=bold>/</> ' : '').'<fg=green;options=bold>Type</>',
  194. '<fg=green;options=bold>Type</> <fg=gray;options=bold>/</> <fg=green;options=bold>Category</>'
  195. );
  196. $types->each(fn ($type) => $this->components->twoColumnDetail(
  197. ($type['schema'] ? $type['schema'].' <fg=gray;options=bold>/</> ' : '').$type['name'],
  198. $type['type'].' <fg=gray;options=bold>/</> '.$type['category']
  199. ));
  200. $this->newLine();
  201. }
  202. }
  203. }