281 lines
6.9 KiB
PHP
281 lines
6.9 KiB
PHP
<?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'],
|
|
];
|
|
}
|
|
}
|