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'], ]; } }