mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-12-05 13:18:22 +08:00
Added seed commands.
This commit is contained in:
parent
9c885f49bf
commit
3b1afc3a2c
44
src/database/src/Commands/Seeders/BaseCommand.php
Normal file
44
src/database/src/Commands/Seeders/BaseCommand.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace Hyperf\Database\Commands\Seeders;
|
||||
|
||||
use Hyperf\Command\Command;
|
||||
|
||||
abstract class BaseCommand extends Command
|
||||
{
|
||||
/**
|
||||
* Get seeder path (either specified by '--path' option or default location).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getSeederPath()
|
||||
{
|
||||
if (! is_null($targetPath = $this->input->getOption('path'))) {
|
||||
return ! $this->usingRealPath()
|
||||
? BASE_PATH . '/' . $targetPath
|
||||
: $targetPath;
|
||||
}
|
||||
|
||||
return BASE_PATH . DIRECTORY_SEPARATOR . 'seeders';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given path(s) are pre-resolved "real" paths.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function usingRealPath()
|
||||
{
|
||||
return $this->input->hasOption('realpath') && $this->input->getOption('realpath');
|
||||
}
|
||||
}
|
91
src/database/src/Commands/Seeders/GenSeederCommand.php
Normal file
91
src/database/src/Commands/Seeders/GenSeederCommand.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace Hyperf\Database\Commands\Seeders;
|
||||
|
||||
use Hyperf\Database\Seeders\SeederCreator;
|
||||
use Hyperf\Utils\Str;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class GenSeederCommand extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* The seeder creator instance.
|
||||
*
|
||||
* @var \Hyperf\Database\Seeders\SeederCreator
|
||||
*/
|
||||
protected $creator;
|
||||
|
||||
/**
|
||||
* Create a new seeder generator command instance.
|
||||
*
|
||||
* @param \Hyperf\Database\Seeders\SeederCreator $creator
|
||||
*/
|
||||
public function __construct(SeederCreator $creator)
|
||||
{
|
||||
parent::__construct('gen:seeder');
|
||||
$this->setDescription('Create a new seeder class');
|
||||
|
||||
$this->creator = $creator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the current command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$name = Str::snake(trim($this->input->getArgument('name')));
|
||||
|
||||
$this->writeMigration($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the seeder file to disk.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
protected function writeMigration(string $name)
|
||||
{
|
||||
$path = $this->ensureSeederDirectoryAlreadyExist(
|
||||
$this->getSeederPath()
|
||||
);
|
||||
|
||||
$file = pathinfo($this->creator->create($name, $path), PATHINFO_FILENAME);
|
||||
|
||||
$this->info("<info>[INFO] Created Seeder:</info> {$file}");
|
||||
}
|
||||
|
||||
protected function ensureSeederDirectoryAlreadyExist(string $path)
|
||||
{
|
||||
if (! file_exists($path)) {
|
||||
mkdir($path, 0755, true);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
protected function getArguments(): array
|
||||
{
|
||||
return [
|
||||
['name', InputArgument::REQUIRED, 'The name of the seeder'],
|
||||
];
|
||||
}
|
||||
|
||||
protected function getOptions(): array
|
||||
{
|
||||
return [
|
||||
['path', null, InputOption::VALUE_OPTIONAL, 'The location where the seeder file should be created'],
|
||||
['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided seeder file paths are pre-resolved absolute paths'],
|
||||
];
|
||||
}
|
||||
}
|
88
src/database/src/Commands/Seeders/SeedCommand.php
Normal file
88
src/database/src/Commands/Seeders/SeedCommand.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace Hyperf\Database\Commands\Seeders;
|
||||
|
||||
use Hyperf\Command\ConfirmableTrait;
|
||||
use Hyperf\Database\Seeders\Seed;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class SeedCommand extends BaseCommand
|
||||
{
|
||||
use ConfirmableTrait;
|
||||
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'db:seed';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Seed the database with records';
|
||||
|
||||
/**
|
||||
* The seed instance.
|
||||
*
|
||||
* @var \Hyperf\Database\Seeders\Seed
|
||||
*/
|
||||
protected $seed;
|
||||
|
||||
/**
|
||||
* Create a new seed command instance.
|
||||
*
|
||||
* @param \Hyperf\Database\Seeders\Seed $seed
|
||||
*/
|
||||
public function __construct(Seed $seed)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->seed = $seed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the current command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (! $this->confirmToProceed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->seed->setOutput($this->output);
|
||||
|
||||
if ($this->input->hasOption('database')) {
|
||||
$this->seed->setConnection($this->input->getOption('database'));
|
||||
}
|
||||
|
||||
$this->seed->run([$this->getSeederPath()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getOptions()
|
||||
{
|
||||
return [
|
||||
['path', null, InputOption::VALUE_OPTIONAL, 'The location where the seeders file stored'],
|
||||
['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided seeder file paths are pre-resolved absolute paths'],
|
||||
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed'],
|
||||
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'],
|
||||
];
|
||||
}
|
||||
}
|
265
src/database/src/Seeders/Seed.php
Normal file
265
src/database/src/Seeders/Seed.php
Normal file
@ -0,0 +1,265 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace Hyperf\Database\Seeders;
|
||||
|
||||
use Hyperf\Database\Connection;
|
||||
use Hyperf\Database\ConnectionResolverInterface as Resolver;
|
||||
use Hyperf\Database\Model\Model;
|
||||
use Hyperf\Database\Schema\Grammars\Grammar;
|
||||
use Hyperf\Utils\Collection;
|
||||
use Hyperf\Utils\Filesystem\Filesystem;
|
||||
use Hyperf\Utils\Str;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Seed
|
||||
{
|
||||
/**
|
||||
* The filesystem instance.
|
||||
*
|
||||
* @var \Hyperf\Utils\Filesystem\Filesystem
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* The connection resolver instance.
|
||||
*
|
||||
* @var \Hyperf\Database\ConnectionResolverInterface
|
||||
*/
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* The name of the default connection.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The paths to all of the seeder files.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $paths = [];
|
||||
|
||||
/**
|
||||
* The output interface implementation.
|
||||
*
|
||||
* @var OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* Create a new seed instance.
|
||||
*
|
||||
* @param \Hyperf\Database\ConnectionResolverInterface $resolver
|
||||
* @param \Hyperf\Utils\Filesystem\Filesystem $files
|
||||
*/
|
||||
public function __construct(Resolver $resolver, Filesystem $files)
|
||||
{
|
||||
$this->files = $files;
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the pending seeders at a given path.
|
||||
*
|
||||
* @param array|string $paths
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
public function run($paths = [], array $options = [])
|
||||
{
|
||||
$files = $this->getSeederFiles($paths);
|
||||
|
||||
$this->requireFiles($files);
|
||||
|
||||
$this->runSeeders($files, $options);
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default connection name.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setConnection(string $name): void
|
||||
{
|
||||
if (! is_null($name)) {
|
||||
$this->resolver->setDefaultConnection($name);
|
||||
}
|
||||
|
||||
$this->connection = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an array of seeders.
|
||||
*
|
||||
* @param array $seeders
|
||||
* @param array $options
|
||||
*/
|
||||
public function runSeeders(array $seeders, array $options = [])
|
||||
{
|
||||
if (count($seeders) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($seeders as $file) {
|
||||
$this->runSeeder($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a seeder.
|
||||
*
|
||||
* @param string $file
|
||||
*/
|
||||
public function runSeeder($file)
|
||||
{
|
||||
Model::unguarded(function () use ($file) {
|
||||
$seeder = $this->resolve(
|
||||
$name = $this->getSeederName($file)
|
||||
);
|
||||
|
||||
$this->note("<comment>Seed:</comment> {$name}");
|
||||
|
||||
$connection = $this->resolveConnection(
|
||||
$seeder->getConnection()
|
||||
);
|
||||
|
||||
$callback = function () use ($seeder) {
|
||||
if (method_exists($seeder, 'run')) {
|
||||
$seeder->run();
|
||||
}
|
||||
};
|
||||
|
||||
if ($this->getSchemaGrammar($connection)->supportsSchemaTransactions() && $seeder->withinTransaction) {
|
||||
$connection->transaction($callback);
|
||||
} else {
|
||||
$callback();
|
||||
}
|
||||
|
||||
$this->note("<info>Seeded:</info> {$name}");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a seeder instance from a file.
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function resolve(string $file): object
|
||||
{
|
||||
$class = Str::studly(implode('_', array_slice(explode('_', $file), 4)));
|
||||
|
||||
return new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the database connection instance.
|
||||
*
|
||||
* @param string $connection
|
||||
*
|
||||
* @return Connection
|
||||
*/
|
||||
public function resolveConnection(string $connection)
|
||||
{
|
||||
return $this->resolver->connection($connection ?: $this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the seeder files in a given path.
|
||||
*
|
||||
* @param string|array $paths
|
||||
* @return array
|
||||
*/
|
||||
public function getSeederFiles($paths)
|
||||
{
|
||||
return Collection::make($paths)->flatMap(function ($path) {
|
||||
return Str::endsWith($path, '.php') ? [$path] : $this->files->glob($path.'/*.php');
|
||||
})->filter()->sortBy(function ($file) {
|
||||
return $this->getSeederName($file);
|
||||
})->values()->keyBy(function ($file) {
|
||||
return $this->getSeederName($file);
|
||||
})->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the seeder.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function getSeederName($path)
|
||||
{
|
||||
return str_replace('.php', '', basename($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Require in all the seeder files in a given path.
|
||||
*
|
||||
* @param array $files
|
||||
*/
|
||||
public function requireFiles(array $files)
|
||||
{
|
||||
foreach ($files as $file) {
|
||||
$this->files->requireOnce($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output implementation that should be used by the console.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @return $this
|
||||
*/
|
||||
public function setOutput(OutputInterface $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the schema grammar out of a migration connection.
|
||||
*
|
||||
* @param Connection $connection
|
||||
*
|
||||
* @return \Hyperf\Database\Schema\Grammars\Grammar
|
||||
*/
|
||||
protected function getSchemaGrammar($connection): Grammar
|
||||
{
|
||||
if (is_null($grammar = $connection->getSchemaGrammar())) {
|
||||
$connection->useDefaultSchemaGrammar();
|
||||
|
||||
$grammar = $connection->getSchemaGrammar();
|
||||
}
|
||||
|
||||
return $grammar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a note to the console's output.
|
||||
*
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
protected function note($message)
|
||||
{
|
||||
if ($this->output) {
|
||||
$this->output->writeln($message);
|
||||
}
|
||||
}
|
||||
}
|
42
src/database/src/Seeders/Seeder.php
Normal file
42
src/database/src/Seeders/Seeder.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace Hyperf\Database\Seeders;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
abstract class Seeder
|
||||
{
|
||||
/**
|
||||
* The name of the database connection to use.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'default';
|
||||
|
||||
/**
|
||||
* Enables, if supported, wrapping the seeder within a transaction.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $withinTransaction = true;
|
||||
|
||||
/**
|
||||
* Get the seeder connection name.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
}
|
138
src/database/src/Seeders/SeederCreator.php
Normal file
138
src/database/src/Seeders/SeederCreator.php
Normal file
@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace Hyperf\Database\Seeders;
|
||||
|
||||
use Hyperf\Utils\Filesystem\Filesystem;
|
||||
use Hyperf\Utils\Str;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class SeederCreator
|
||||
{
|
||||
/**
|
||||
* The filesystem instance.
|
||||
*
|
||||
* @var Filesystem
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* Create a new seeder creator instance.
|
||||
*
|
||||
* @param Filesystem $files
|
||||
*/
|
||||
public function __construct(Filesystem $files)
|
||||
{
|
||||
$this->files = $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new seeder at the given path.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function create($name, $path)
|
||||
{
|
||||
$this->ensureSeederDoesntAlreadyExist($name);
|
||||
|
||||
$stub = $this->getStub();
|
||||
|
||||
$this->files->put(
|
||||
$path = $this->getPath($name, $path),
|
||||
$this->populateStub($name, $stub)
|
||||
);
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the seeder stub file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getStub()
|
||||
{
|
||||
return $this->files->get($this->stubPath().'/seeder.stub');
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the place-holders in the seeder stub.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $stub
|
||||
* @return string
|
||||
*/
|
||||
protected function populateStub($name, $stub)
|
||||
{
|
||||
return str_replace('DummyClass', $this->getClassName($name), $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a seeder with the given name doesn't already exist.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function ensureSeederDoesntAlreadyExist($name)
|
||||
{
|
||||
if (class_exists($className = $this->getClassName($name))) {
|
||||
throw new InvalidArgumentException("A {$className} class already exists.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class name of a seeder name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
protected function getClassName($name)
|
||||
{
|
||||
return Str::studly($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full path to the seeder.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
protected function getPath($name, $path)
|
||||
{
|
||||
return $path.'/'.$name.'.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the stubs.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function stubPath()
|
||||
{
|
||||
return __DIR__.'/stubs';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filesystem instance.
|
||||
*
|
||||
* @return \Hyperf\Utils\Filesystem\Filesystem
|
||||
*/
|
||||
public function getFilesystem()
|
||||
{
|
||||
return $this->files;
|
||||
}
|
||||
}
|
18
src/database/src/Seeders/stubs/seeder.stub
Normal file
18
src/database/src/Seeders/stubs/seeder.stub
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Hyperf\Database\Seeders\Seeder;
|
||||
|
||||
class DummyClass extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ use Hyperf\Database\Commands\Migrations\ResetCommand;
|
||||
use Hyperf\Database\Commands\Migrations\RollbackCommand;
|
||||
use Hyperf\Database\Commands\Migrations\StatusCommand;
|
||||
use Hyperf\Database\Commands\ModelCommand;
|
||||
use Hyperf\Database\Commands\Seeders\GenSeederCommand;
|
||||
use Hyperf\Database\Commands\Seeders\SeedCommand;
|
||||
use Hyperf\Database\ConnectionResolverInterface;
|
||||
use Hyperf\Database\Connectors\ConnectionFactory;
|
||||
use Hyperf\Database\Connectors\MySqlConnector;
|
||||
@ -49,6 +51,8 @@ class ConfigProvider
|
||||
ResetCommand::class,
|
||||
RollbackCommand::class,
|
||||
StatusCommand::class,
|
||||
GenSeederCommand::class,
|
||||
SeedCommand::class,
|
||||
],
|
||||
'scan' => [
|
||||
'paths' => [
|
||||
|
Loading…
Reference in New Issue
Block a user