DbCommand.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <?php
  2. namespace Illuminate\Database\Console;
  3. use Illuminate\Console\Command;
  4. use Illuminate\Support\ConfigurationUrlParser;
  5. use Symfony\Component\Console\Attribute\AsCommand;
  6. use Symfony\Component\Process\Process;
  7. use UnexpectedValueException;
  8. #[AsCommand(name: 'db')]
  9. class DbCommand extends Command
  10. {
  11. /**
  12. * The name and signature of the console command.
  13. *
  14. * @var string
  15. */
  16. protected $signature = 'db {connection? : The database connection that should be used}
  17. {--read : Connect to the read connection}
  18. {--write : Connect to the write connection}';
  19. /**
  20. * The console command description.
  21. *
  22. * @var string
  23. */
  24. protected $description = 'Start a new database CLI session';
  25. /**
  26. * Execute the console command.
  27. *
  28. * @return int
  29. */
  30. public function handle()
  31. {
  32. $connection = $this->getConnection();
  33. if (! isset($connection['host']) && $connection['driver'] !== 'sqlite') {
  34. $this->components->error('No host specified for this database connection.');
  35. $this->line(' Use the <options=bold>[--read]</> and <options=bold>[--write]</> options to specify a read or write connection.');
  36. $this->newLine();
  37. return Command::FAILURE;
  38. }
  39. (new Process(
  40. array_merge([$this->getCommand($connection)], $this->commandArguments($connection)),
  41. null,
  42. $this->commandEnvironment($connection)
  43. ))->setTimeout(null)->setTty(true)->mustRun(function ($type, $buffer) {
  44. $this->output->write($buffer);
  45. });
  46. return 0;
  47. }
  48. /**
  49. * Get the database connection configuration.
  50. *
  51. * @return array
  52. *
  53. * @throws \UnexpectedValueException
  54. */
  55. public function getConnection()
  56. {
  57. $connection = $this->laravel['config']['database.connections.'.
  58. (($db = $this->argument('connection')) ?? $this->laravel['config']['database.default'])
  59. ];
  60. if (empty($connection)) {
  61. throw new UnexpectedValueException("Invalid database connection [{$db}].");
  62. }
  63. if (! empty($connection['url'])) {
  64. $connection = (new ConfigurationUrlParser)->parseConfiguration($connection);
  65. }
  66. if ($this->option('read')) {
  67. if (is_array($connection['read']['host'])) {
  68. $connection['read']['host'] = $connection['read']['host'][0];
  69. }
  70. $connection = array_merge($connection, $connection['read']);
  71. } elseif ($this->option('write')) {
  72. if (is_array($connection['write']['host'])) {
  73. $connection['write']['host'] = $connection['write']['host'][0];
  74. }
  75. $connection = array_merge($connection, $connection['write']);
  76. }
  77. return $connection;
  78. }
  79. /**
  80. * Get the arguments for the database client command.
  81. *
  82. * @param array $connection
  83. * @return array
  84. */
  85. public function commandArguments(array $connection)
  86. {
  87. $driver = ucfirst($connection['driver']);
  88. return $this->{"get{$driver}Arguments"}($connection);
  89. }
  90. /**
  91. * Get the environment variables for the database client command.
  92. *
  93. * @param array $connection
  94. * @return array|null
  95. */
  96. public function commandEnvironment(array $connection)
  97. {
  98. $driver = ucfirst($connection['driver']);
  99. if (method_exists($this, "get{$driver}Environment")) {
  100. return $this->{"get{$driver}Environment"}($connection);
  101. }
  102. return null;
  103. }
  104. /**
  105. * Get the database client command to run.
  106. *
  107. * @param array $connection
  108. * @return string
  109. */
  110. public function getCommand(array $connection)
  111. {
  112. return [
  113. 'mysql' => 'mysql',
  114. 'mariadb' => 'mysql',
  115. 'pgsql' => 'psql',
  116. 'sqlite' => 'sqlite3',
  117. 'sqlsrv' => 'sqlcmd',
  118. ][$connection['driver']];
  119. }
  120. /**
  121. * Get the arguments for the MySQL CLI.
  122. *
  123. * @param array $connection
  124. * @return array
  125. */
  126. protected function getMysqlArguments(array $connection)
  127. {
  128. return array_merge([
  129. '--host='.$connection['host'],
  130. '--port='.$connection['port'],
  131. '--user='.$connection['username'],
  132. ], $this->getOptionalArguments([
  133. 'password' => '--password='.$connection['password'],
  134. 'unix_socket' => '--socket='.($connection['unix_socket'] ?? ''),
  135. 'charset' => '--default-character-set='.($connection['charset'] ?? ''),
  136. ], $connection), [$connection['database']]);
  137. }
  138. /**
  139. * Get the arguments for the MariaDB CLI.
  140. *
  141. * @param array $connection
  142. * @return array
  143. */
  144. protected function getMariaDbArguments(array $connection)
  145. {
  146. return $this->getMysqlArguments($connection);
  147. }
  148. /**
  149. * Get the arguments for the Postgres CLI.
  150. *
  151. * @param array $connection
  152. * @return array
  153. */
  154. protected function getPgsqlArguments(array $connection)
  155. {
  156. return [$connection['database']];
  157. }
  158. /**
  159. * Get the arguments for the SQLite CLI.
  160. *
  161. * @param array $connection
  162. * @return array
  163. */
  164. protected function getSqliteArguments(array $connection)
  165. {
  166. return [$connection['database']];
  167. }
  168. /**
  169. * Get the arguments for the SQL Server CLI.
  170. *
  171. * @param array $connection
  172. * @return array
  173. */
  174. protected function getSqlsrvArguments(array $connection)
  175. {
  176. return array_merge(...$this->getOptionalArguments([
  177. 'database' => ['-d', $connection['database']],
  178. 'username' => ['-U', $connection['username']],
  179. 'password' => ['-P', $connection['password']],
  180. 'host' => ['-S', 'tcp:'.$connection['host']
  181. .($connection['port'] ? ','.$connection['port'] : ''), ],
  182. 'trust_server_certificate' => ['-C'],
  183. ], $connection));
  184. }
  185. /**
  186. * Get the environment variables for the Postgres CLI.
  187. *
  188. * @param array $connection
  189. * @return array|null
  190. */
  191. protected function getPgsqlEnvironment(array $connection)
  192. {
  193. return array_merge(...$this->getOptionalArguments([
  194. 'username' => ['PGUSER' => $connection['username']],
  195. 'host' => ['PGHOST' => $connection['host']],
  196. 'port' => ['PGPORT' => $connection['port']],
  197. 'password' => ['PGPASSWORD' => $connection['password']],
  198. ], $connection));
  199. }
  200. /**
  201. * Get the optional arguments based on the connection configuration.
  202. *
  203. * @param array $args
  204. * @param array $connection
  205. * @return array
  206. */
  207. protected function getOptionalArguments(array $args, array $connection)
  208. {
  209. return array_values(array_filter($args, function ($key) use ($connection) {
  210. return ! empty($connection[$key]);
  211. }, ARRAY_FILTER_USE_KEY));
  212. }
  213. }