This commit is contained in:
280
api/app/Console/Commands/SeedCommand.php
Normal file
280
api/app/Console/Commands/SeedCommand.php
Normal file
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Console\ConfirmableTrait;
|
||||
use Illuminate\Database\ConnectionResolverInterface as Resolver;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class SeedCommand extends Command
|
||||
{
|
||||
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 connection resolver instance.
|
||||
*
|
||||
* @var \Illuminate\Database\ConnectionResolverInterface
|
||||
*/
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* The filesystem instance.
|
||||
*
|
||||
* @var \Illuminate\Filesystem\Filesystem
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* Create a new database seed command instance.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionResolverInterface $resolver
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Resolver $resolver)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->resolver = $resolver;
|
||||
$this->files = new Filesystem();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (! $this->confirmToProceed()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$previousConnection = $this->resolver->getDefaultConnection();
|
||||
|
||||
$this->resolver->setDefaultConnection($this->getDatabase());
|
||||
|
||||
Schema::disableForeignKeyConstraints();
|
||||
|
||||
self::getSeedersClasses()->each(function ($class) {
|
||||
Model::unguarded(function () use ($class) {
|
||||
|
||||
$this->getOutput()->writeln("<comment>Seeding:</comment> {$class['file_name']}");
|
||||
|
||||
$startTime = microtime(true);
|
||||
|
||||
$this->getSeeder(class_basename($class['instance']))->__invoke();
|
||||
|
||||
$runTime = number_format((microtime(true) - $startTime) * 1000, 2);
|
||||
|
||||
$this->getOutput()->writeln("<info>Seeded:</info> {$class['file_name']} ({$runTime}ms)");
|
||||
|
||||
DB::connection($this->getDatabase())->table('seeders')->insert(['seeder' => $class['file_name']]);
|
||||
});
|
||||
});
|
||||
|
||||
Schema::enableForeignKeyConstraints();
|
||||
|
||||
if ($previousConnection) {
|
||||
$this->resolver->setDefaultConnection($previousConnection);
|
||||
}
|
||||
|
||||
$this->info('Database seeding completed successfully.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function getSeedersClasses()
|
||||
{
|
||||
$ran = DB::connection($this->getDatabase())->table('seeders')->select('seeder')->pluck('seeder')->all();
|
||||
$files = $this->getSeederFiles();
|
||||
|
||||
$this->requireFiles($seeders = $this->pendingSeeders(
|
||||
$files, $ran
|
||||
));
|
||||
|
||||
$classes = collect();
|
||||
|
||||
foreach ($seeders as $file) {
|
||||
|
||||
$fileName = $this->getSeederName($file);
|
||||
|
||||
$classes->push([
|
||||
'file_name' => $fileName,
|
||||
'instance' => $this->resolve($fileName)
|
||||
]);
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the seeder files.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSeederFiles()
|
||||
{
|
||||
return Collection::make(self::getSeederPaths())->flatMap(function ($path) {
|
||||
return Str::endsWith($path, '.php') ? [$path] : $this->files->glob($path.'/*_*.php');
|
||||
})->filter()->values()->keyBy(function ($file) {
|
||||
return $this->getSeederName($file);
|
||||
})->sortBy(function ($file, $key) {
|
||||
return $key;
|
||||
})->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get seeder path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getSeederPaths()
|
||||
{
|
||||
$invalidContents = ['.', '..', '.gitkeep', 'base'];
|
||||
$seedersDir = database_path() . '/seeders/';
|
||||
|
||||
return $this->getSeederFilesPaths(
|
||||
$invalidContents,
|
||||
$seedersDir
|
||||
);
|
||||
}
|
||||
|
||||
private function getSeederFilesPaths($invalidContents, $currentDirectory, $paths = [])
|
||||
{
|
||||
$contents = opendir($currentDirectory);
|
||||
|
||||
while ($content = readdir($contents)) {
|
||||
|
||||
if (!in_array($content, $invalidContents)) {
|
||||
|
||||
$fullPath = $currentDirectory . $content;
|
||||
|
||||
if (is_dir($fullPath)) {
|
||||
|
||||
$paths = $this->getSeederFilesPaths(
|
||||
$invalidContents,
|
||||
$fullPath . '/',
|
||||
$paths
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$paths[] = $fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
return $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require in all the seeder files in a given path.
|
||||
*
|
||||
* @param array $files
|
||||
* @return void
|
||||
*/
|
||||
public function requireFiles(array $files)
|
||||
{
|
||||
foreach ($files as $file) {
|
||||
$this->files->requireOnce($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a seeder instance from a file.
|
||||
*
|
||||
* @param string $file
|
||||
* @return object
|
||||
*/
|
||||
public function resolve($file)
|
||||
{
|
||||
$fileArr = explode('_', $file);
|
||||
$class = Str::studly(implode('_', array_slice($fileArr, 4))).'_'.implode(array_slice($fileArr, 0, 4));
|
||||
|
||||
return new $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the seeder.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public function getSeederName($path)
|
||||
{
|
||||
return str_replace('.php', '', basename($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the seeder files that have not yet run.
|
||||
*
|
||||
* @param array $files
|
||||
* @param array $ran
|
||||
* @return array
|
||||
*/
|
||||
protected function pendingSeeders($files, $ran)
|
||||
{
|
||||
return Collection::make($files)
|
||||
->reject(function ($file) use ($ran) {
|
||||
return in_array($this->getSeederName($file), $ran);
|
||||
})->values()->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a seeder instance from the container.
|
||||
* @param string $class
|
||||
* @return \Illuminate\Database\Seeder
|
||||
*/
|
||||
protected function getSeeder($class)
|
||||
{
|
||||
return $this->laravel->make($class)
|
||||
->setContainer($this->laravel)
|
||||
->setCommand($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the database connection to use.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDatabase()
|
||||
{
|
||||
$database = $this->input->getOption('database');
|
||||
|
||||
return $database ?: $this->laravel['config']['database.default'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getOptions()
|
||||
{
|
||||
return [
|
||||
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed'],
|
||||
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user