123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- <?php
- namespace Dcat\Admin\Console;
- use Dcat\Admin\Support\Helper;
- use Illuminate\Console\Concerns\CreatesMatchingTest;
- use Illuminate\Console\Command;
- use Illuminate\Filesystem\Filesystem;
- use Illuminate\Support\Str;
- use Symfony\Component\Console\Input\InputArgument;
- abstract class GeneratorCommand extends Command
- {
- protected $baseDirectory;
- /**
- * 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',
- 'eval',
- 'exit',
- 'extends',
- 'final',
- 'finally',
- 'fn',
- 'for',
- 'foreach',
- 'function',
- 'global',
- 'goto',
- 'if',
- 'implements',
- 'include',
- 'include_once',
- 'instanceof',
- 'insteadof',
- 'interface',
- 'isset',
- 'list',
- 'namespace',
- 'new',
- 'or',
- 'print',
- 'private',
- 'protected',
- 'public',
- 'require',
- 'require_once',
- 'return',
- 'static',
- 'switch',
- 'throw',
- 'trait',
- 'try',
- 'unset',
- 'use',
- 'var',
- 'while',
- 'xor',
- 'yield',
- ];
- /**
- * 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->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->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)));
- $this->info($this->type.' created successfully.');
- if (in_array(CreatesMatchingTest::class, class_uses_recursive($this))) {
- $this->handleTestCreation($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)));
- }
- /**
- * 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 \Illuminate\Console\GeneratorCommand
- */
- 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 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'],
- ];
- }
- /**
- * Get the root namespace for the class.
- *
- * @return string
- */
- protected function rootNamespace()
- {
- return $this->getDefaultNamespace(null);
- }
- /**
- * Get the destination class path.
- *
- * @param string $name
- * @return string
- */
- protected function getPath($name)
- {
- return Helper::guessClassFileName($name);
- }
- /**
- * @return string
- */
- protected function getBaseDir()
- {
- if ($this->baseDirectory) {
- return trim(base_path($this->baseDirectory), '/');
- }
- if ($this->hasOption('base') && $this->option('base')) {
- return trim(base_path($this->option('base')), '/');
- }
- return $this->laravel['path'];
- }
- /**
- * @return void
- */
- protected function askBaseDirectory()
- {
- if (! Str::startsWith(config('admin.route.namespace'), 'App')) {
- $dir = explode('\\', config('admin.route.namespace'))[0];
- $this->baseDirectory = trim($this->ask('Please enter the application path', Helper::slug($dir)));
- }
- }
- }
|