diff --git a/src/Illuminate/Database/Console/DbDumpCommand.php b/src/Illuminate/Database/Console/DbDumpCommand.php new file mode 100644 index 000000000000..07753946fa28 --- /dev/null +++ b/src/Illuminate/Database/Console/DbDumpCommand.php @@ -0,0 +1,80 @@ +connection($database = $this->input->getOption('database')); + + $this->schemaState($connection)->dump( + $connection, $path = $this->path($connection) + ); + + $dispatcher->dispatch(new DatabaseDumped($connection, $path)); + + $info = 'Database dumped'; + + $this->components->info($info.' successfully to '.$path); + } + + /** + * Create a schema state instance for the given connection. + * + * @param \Illuminate\Database\Connection $connection + * @return mixed + */ + protected function schemaState(Connection $connection) + { + return $connection->getSchemaState() + ->withData() + ->handleOutputUsing(function ($type, $buffer) { + $this->output->write($buffer); + }); + } + + /** + * Get the path that the dump should be written to. + * + * @param \Illuminate\Database\Connection $connection + */ + protected function path(Connection $connection) + { + return tap($this->option('path') ?: storage_path($connection->getName().'-'.date('Ymdhis').'.sql'), function ($path) { + (new Filesystem)->ensureDirectoryExists(dirname($path)); + }); + } +} diff --git a/src/Illuminate/Database/Console/DbLoadCommand.php b/src/Illuminate/Database/Console/DbLoadCommand.php new file mode 100644 index 000000000000..718ae977a82f --- /dev/null +++ b/src/Illuminate/Database/Console/DbLoadCommand.php @@ -0,0 +1,83 @@ +isProhibited() || + ! $this->confirmToProceed()) { + return Command::FAILURE; + } + + $connection = $connections->connection($database = $this->input->getOption('database')); + + $path = $this->argument('path'); + + if ($this->input->getOption('drop')) { + $this->call('db:wipe', array_filter([ + '--database' => $database, + '--force' => true, + ])); + } + + $this->schemaState($connection)->load($path); + + $dispatcher->dispatch(new DatabaseLoaded($connection, $path)); + + $info = 'Database loaded'; + + $this->components->info($info.' successfully in database '.$connection->getDatabaseName()); + } + + /** + * Create a schema state instance for the given connection. + * + * @param \Illuminate\Database\Connection $connection + * @return mixed + */ + protected function schemaState(Connection $connection) + { + return $connection->getSchemaState() + ->handleOutputUsing(function ($type, $buffer) { + $this->output->write($buffer); + }); + } +} diff --git a/src/Illuminate/Database/Events/DatabaseDumped.php b/src/Illuminate/Database/Events/DatabaseDumped.php new file mode 100644 index 000000000000..7dd6c0780e41 --- /dev/null +++ b/src/Illuminate/Database/Events/DatabaseDumped.php @@ -0,0 +1,40 @@ +connection = $connection; + $this->connectionName = $connection->getName(); + $this->path = $path; + } +} diff --git a/src/Illuminate/Database/Events/DatabaseLoaded.php b/src/Illuminate/Database/Events/DatabaseLoaded.php new file mode 100644 index 000000000000..e9d7be9ad248 --- /dev/null +++ b/src/Illuminate/Database/Events/DatabaseLoaded.php @@ -0,0 +1,40 @@ +connection = $connection; + $this->connectionName = $connection->getName(); + $this->path = $path; + } +} diff --git a/src/Illuminate/Database/Schema/MySqlSchemaState.php b/src/Illuminate/Database/Schema/MySqlSchemaState.php index 427c943ff736..d1eaa7596000 100644 --- a/src/Illuminate/Database/Schema/MySqlSchemaState.php +++ b/src/Illuminate/Database/Schema/MySqlSchemaState.php @@ -18,16 +18,23 @@ class MySqlSchemaState extends SchemaState */ public function dump(Connection $connection, $path) { - $this->executeDumpProcess($this->makeProcess( - $this->baseDumpCommand().' --routines --result-file="${:LARAVEL_LOAD_PATH}" --no-data' - ), $this->output, array_merge($this->baseVariables($this->connection->getConfig()), [ + $dumpCommand = $this->baseDumpCommand().' --routines --result-file="${:LARAVEL_LOAD_PATH}"'; + + if ($this->hasData()) { + $dumpCommand .= ' --single-transaction --quick'; + } else { + $dumpCommand .= ' --no-data'; + } + $this->executeDumpProcess($this->makeProcess($dumpCommand), $this->output, array_merge($this->baseVariables($this->connection->getConfig()), [ 'LARAVEL_LOAD_PATH' => $path, ])); - $this->removeAutoIncrementingState($path); + if (! $this->hasData()) { + $this->removeAutoIncrementingState($path); - if ($this->hasMigrationTable()) { - $this->appendMigrationData($path); + if ($this->hasMigrationTable()) { + $this->appendMigrationData($path); + } } } diff --git a/src/Illuminate/Database/Schema/PostgresSchemaState.php b/src/Illuminate/Database/Schema/PostgresSchemaState.php index 25da812e61c5..375135a521cd 100644 --- a/src/Illuminate/Database/Schema/PostgresSchemaState.php +++ b/src/Illuminate/Database/Schema/PostgresSchemaState.php @@ -16,11 +16,18 @@ class PostgresSchemaState extends SchemaState */ public function dump(Connection $connection, $path) { + $dumpCommand = $this->baseDumpCommand(); + if ($this->hasData()) { + $dumpCommand .= ' --column-inserts'; + } else { + $dumpCommand .= ' ---schema-only'; + } + $commands = new Collection([ - $this->baseDumpCommand().' --schema-only > '.$path, + $dumpCommand.' > '.$path, ]); - if ($this->hasMigrationTable()) { + if (! $this->hasData() && $this->hasMigrationTable()) { $commands->push($this->baseDumpCommand().' -t '.$this->getMigrationTable().' --data-only >> '.$path); } diff --git a/src/Illuminate/Database/Schema/SchemaState.php b/src/Illuminate/Database/Schema/SchemaState.php index be792138f7b4..8373bb8ccbfd 100644 --- a/src/Illuminate/Database/Schema/SchemaState.php +++ b/src/Illuminate/Database/Schema/SchemaState.php @@ -29,6 +29,13 @@ abstract class SchemaState */ protected $migrationTable = 'migrations'; + /** + * Indicates if the dumper should include data. + * + * @var bool + */ + protected $data = false; + /** * The process factory callback. * @@ -126,6 +133,29 @@ public function withMigrationTable(string $table) return $this; } + /** + * Check if the dumper should include data. + * + * @return bool + */ + public function hasData() + { + return $this->data; + } + + /** + * Indicate that the dumper should include data. + * + * @param bool $data + * @return $this + */ + public function withData(bool $data = true) + { + $this->data = $data; + + return $this; + } + /** * Specify the callback that should be used to handle process output. * diff --git a/src/Illuminate/Database/Schema/SqliteSchemaState.php b/src/Illuminate/Database/Schema/SqliteSchemaState.php index 3d954a39de17..19caaccfc850 100644 --- a/src/Illuminate/Database/Schema/SqliteSchemaState.php +++ b/src/Illuminate/Database/Schema/SqliteSchemaState.php @@ -16,18 +16,27 @@ class SqliteSchemaState extends SchemaState */ public function dump(Connection $connection, $path) { - $process = $this->makeProcess($this->baseCommand().' ".schema --indent"') + if ($this->hasData()) { + $dumpCommand = $this->baseCommand().' -batch ".dump"'; + } else { + $dumpCommand = $this->baseCommand().' ".schema --indent"'; + } + $process = $this->makeProcess($dumpCommand) ->setTimeout(null) ->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [ // ])); - $migrations = preg_replace('/CREATE TABLE sqlite_.+?\);[\r\n]+/is', '', $process->getOutput()); + if (! $this->hasData()) { + $migrations = preg_replace('/CREATE TABLE sqlite_.+?\);[\r\n]+/is', '', $process->getOutput()); - $this->files->put($path, $migrations.PHP_EOL); + $this->files->put($path, $migrations.PHP_EOL); - if ($this->hasMigrationTable()) { - $this->appendMigrationData($path); + if ($this->hasMigrationTable()) { + $this->appendMigrationData($path); + } + } else { + $this->files->put($path, $process->getOutput()); } } diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index d2ae86019342..a96d23530166 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -18,6 +18,8 @@ use Illuminate\Console\Signals; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Database\Console\DbCommand; +use Illuminate\Database\Console\DbDumpCommand; +use Illuminate\Database\Console\DbLoadCommand; use Illuminate\Database\Console\DumpCommand; use Illuminate\Database\Console\Factories\FactoryMakeCommand; use Illuminate\Database\Console\MonitorCommand as DatabaseMonitorCommand; @@ -126,6 +128,8 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'ConfigClear' => ConfigClearCommand::class, 'ConfigShow' => ConfigShowCommand::class, 'Db' => DbCommand::class, + 'DbDump' => DbDumpCommand::class, + 'DbLoad' => DbLoadCommand::class, 'DbMonitor' => DatabaseMonitorCommand::class, 'DbPrune' => PruneCommand::class, 'DbShow' => ShowCommand::class,