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("Seeding: {$class['file_name']}");
$startTime = microtime(true);
$this->getSeeder(class_basename($class['instance']))->__invoke();
$runTime = number_format((microtime(true) - $startTime) * 1000, 2);
$this->getOutput()->writeln("Seeded: {$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'],
];
}
}