Revision 399 | Zur aktuellen Revision | Blame | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed
<?phpnamespace Illuminate\Console;use Illuminate\Console\Concerns\CreatesMatchingTest;use Illuminate\Filesystem\Filesystem;use Illuminate\Support\Str;use Symfony\Component\Console\Input\InputArgument;abstract class GeneratorCommand extends Command{/*** The filesystem instance.** @var \Illuminate\Filesystem\Filesystem*/protected $files;/*** The type of class being generated.** @var string*/protected $type;/*** Reserved names that cannot be used for generation.** @var string[]*/protected $reservedNames = ['__halt_compiler','abstract','and','array','as','break','callable','case','catch','class','clone','const','continue','declare','default','die','do','echo','else','elseif','empty','enddeclare','endfor','endforeach','endif','endswitch','endwhile','enum','eval','exit','extends','false','final','finally','fn','for','foreach','function','global','goto','if','implements','include','include_once','instanceof','insteadof','interface','isset','list','match','namespace','new','or','print','private','protected','public','readonly','require','require_once','return','static','switch','throw','trait','true','try','unset','use','var','while','xor','yield','__CLASS__','__DIR__','__FILE__','__FUNCTION__','__LINE__','__METHOD__','__NAMESPACE__','__TRAIT__',];/*** Create a new controller creator command instance.** @param \Illuminate\Filesystem\Filesystem $files* @return void*/public function __construct(Filesystem $files){parent::__construct();if (in_array(CreatesMatchingTest::class, class_uses_recursive($this))) {$this->addTestOptions();}$this->files = $files;}/*** Get the stub file for the generator.** @return string*/abstract protected function getStub();/*** Execute the console command.** @return bool|null** @throws \Illuminate\Contracts\Filesystem\FileNotFoundException*/public function handle(){// First we need to ensure that the given name is not a reserved word within the PHP// language and that the class name will actually be valid. If it is not valid we// can error now and prevent from polluting the filesystem using invalid files.if ($this->isReservedName($this->getNameInput())) {$this->components->error('The name "'.$this->getNameInput().'" is reserved by PHP.');return false;}$name = $this->qualifyClass($this->getNameInput());$path = $this->getPath($name);// Next, We will check to see if the class already exists. If it does, we don't want// to create the class and overwrite the user's code. So, we will bail out so the// code is untouched. Otherwise, we will continue generating this class' files.if ((! $this->hasOption('force') ||! $this->option('force')) &&$this->alreadyExists($this->getNameInput())) {$this->components->error($this->type.' already exists.');return false;}// Next, we will generate the path to the location where this class' file should get// written. Then, we will build the class and make the proper replacements on the// stub files so that it gets the correctly formatted namespace and class name.$this->makeDirectory($path);$this->files->put($path, $this->sortImports($this->buildClass($name)));$info = $this->type;if (in_array(CreatesMatchingTest::class, class_uses_recursive($this))) {if ($this->handleTestCreation($path)) {$info .= ' and test';}}$this->components->info(sprintf('%s [%s] created successfully.', $info, $path));}/*** Parse the class name and format according to the root namespace.** @param string $name* @return string*/protected function qualifyClass($name){$name = ltrim($name, '\\/');$name = str_replace('/', '\\', $name);$rootNamespace = $this->rootNamespace();if (Str::startsWith($name, $rootNamespace)) {return $name;}return $this->qualifyClass($this->getDefaultNamespace(trim($rootNamespace, '\\')).'\\'.$name);}/*** Qualify the given model class base name.** @param string $model* @return string*/protected function qualifyModel(string $model){$model = ltrim($model, '\\/');$model = str_replace('/', '\\', $model);$rootNamespace = $this->rootNamespace();if (Str::startsWith($model, $rootNamespace)) {return $model;}return is_dir(app_path('Models'))? $rootNamespace.'Models\\'.$model: $rootNamespace.$model;}/*** Get the default namespace for the class.** @param string $rootNamespace* @return string*/protected function getDefaultNamespace($rootNamespace){return $rootNamespace;}/*** Determine if the class already exists.** @param string $rawName* @return bool*/protected function alreadyExists($rawName){return $this->files->exists($this->getPath($this->qualifyClass($rawName)));}/*** Get the destination class path.** @param string $name* @return string*/protected function getPath($name){$name = Str::replaceFirst($this->rootNamespace(), '', $name);return $this->laravel['path'].'/'.str_replace('\\', '/', $name).'.php';}/*** Build the directory for the class if necessary.** @param string $path* @return string*/protected function makeDirectory($path){if (! $this->files->isDirectory(dirname($path))) {$this->files->makeDirectory(dirname($path), 0777, true, true);}return $path;}/*** Build the class with the given name.** @param string $name* @return string** @throws \Illuminate\Contracts\Filesystem\FileNotFoundException*/protected function buildClass($name){$stub = $this->files->get($this->getStub());return $this->replaceNamespace($stub, $name)->replaceClass($stub, $name);}/*** Replace the namespace for the given stub.** @param string $stub* @param string $name* @return $this*/protected function replaceNamespace(&$stub, $name){$searches = [['DummyNamespace', 'DummyRootNamespace', 'NamespacedDummyUserModel'],['{{ namespace }}', '{{ rootNamespace }}', '{{ namespacedUserModel }}'],['{{namespace}}', '{{rootNamespace}}', '{{namespacedUserModel}}'],];foreach ($searches as $search) {$stub = str_replace($search,[$this->getNamespace($name), $this->rootNamespace(), $this->userProviderModel()],$stub);}return $this;}/*** Get the full namespace for a given class, without the class name.** @param string $name* @return string*/protected function getNamespace($name){return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');}/*** Replace the class name for the given stub.** @param string $stub* @param string $name* @return string*/protected function replaceClass($stub, $name){$class = str_replace($this->getNamespace($name).'\\', '', $name);return str_replace(['DummyClass', '{{ class }}', '{{class}}'], $class, $stub);}/*** Alphabetically sorts the imports for the given stub.** @param string $stub* @return string*/protected function sortImports($stub){if (preg_match('/(?P<imports>(?:^use [^;{]+;$\n?)+)/m', $stub, $match)) {$imports = explode("\n", trim($match['imports']));sort($imports);return str_replace(trim($match['imports']), implode("\n", $imports), $stub);}return $stub;}/*** Get the desired class name from the input.** @return string*/protected function getNameInput(){return trim($this->argument('name'));}/*** Get the root namespace for the class.** @return string*/protected function rootNamespace(){return $this->laravel->getNamespace();}/*** Get the model for the default guard's user provider.** @return string|null*/protected function userProviderModel(){$config = $this->laravel['config'];$provider = $config->get('auth.guards.'.$config->get('auth.defaults.guard').'.provider');return $config->get("auth.providers.{$provider}.model");}/*** Checks whether the given name is reserved.** @param string $name* @return bool*/protected function isReservedName($name){$name = strtolower($name);return in_array($name, $this->reservedNames);}/*** Get the first view directory path from the application configuration.** @param string $path* @return string*/protected function viewPath($path = ''){$views = $this->laravel['config']['view.paths'][0] ?? resource_path('views');return $views.($path ? DIRECTORY_SEPARATOR.$path : $path);}/*** Get the console command arguments.** @return array*/protected function getArguments(){return [['name', InputArgument::REQUIRED, 'The name of the class'],];}}