From fd95610566ef4bbeef164be1b94ba9efd42d9c16 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Tue, 8 Mar 2022 20:48:30 -0600 Subject: [PATCH 1/6] Initial work on improving the alignment of scaffolding with Laravel --- src/Console/Command.php | 17 ++ .../Providers/ArtisanServiceProvider.php | 17 +- src/Scaffold/GeneratorCommand.php | 227 ------------------ src/Support/aliases.php | 5 - tests/Scaffold/ScaffoldBaseTest.php | 4 +- 5 files changed, 35 insertions(+), 235 deletions(-) delete mode 100644 src/Scaffold/GeneratorCommand.php diff --git a/src/Console/Command.php b/src/Console/Command.php index f1b117180..c8aaf0166 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -13,6 +13,23 @@ */ abstract class Command extends BaseCommand { + /** + * @var array List of commands that this command replaces (aliases) + */ + protected $replaces = []; + + /** + * Create a new command instance. + */ + public function __construct() + { + parent::__construct(); + + if (!empty($this->replaces)) { + $this->setAliases($this->replaces); + } + } + /** * Write a string in an alert box. * diff --git a/src/Foundation/Providers/ArtisanServiceProvider.php b/src/Foundation/Providers/ArtisanServiceProvider.php index 6f680fa27..7d23dc970 100644 --- a/src/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Foundation/Providers/ArtisanServiceProvider.php @@ -80,7 +80,9 @@ class ArtisanServiceProvider extends ArtisanServiceProviderBase // 'CastMake' => CastMakeCommand::class, // 'ChannelMake' => ChannelMakeCommand::class, // 'ComponentMake' => ComponentMakeCommand::class, - // 'ConsoleMake' => ConsoleMakeCommand::class, + + + // 'ControllerMake' => ControllerMakeCommand::class, // 'EventGenerate' => EventGenerateCommand::class, // 'EventMake' => EventMakeCommand::class, @@ -90,7 +92,20 @@ class ArtisanServiceProvider extends ArtisanServiceProviderBase // 'ListenerMake' => ListenerMakeCommand::class, // 'MailMake' => MailMakeCommand::class, // 'MiddlewareMake' => MiddlewareMakeCommand::class, + // 'ModelMake' => ModelMakeCommand::class, + + // MigrationServiceProvider + // 'Migrate' => MigrateCommand::class, + // 'MigrateFresh' => FreshCommand::class, + // 'MigrateInstall' => InstallCommand::class, + // 'MigrateRefresh' => RefreshCommand::class, + // 'MigrateReset' => ResetCommand::class, + // 'MigrateRollback' => RollbackCommand::class, + // 'MigrateStatus' => StatusCommand::class, + // 'MigrateMake' => MigrateMakeCommand::class, + + // 'NotificationMake' => NotificationMakeCommand::class, // 'NotificationTable' => NotificationTableCommand::class, // 'ObserverMake' => ObserverMakeCommand::class, diff --git a/src/Scaffold/GeneratorCommand.php b/src/Scaffold/GeneratorCommand.php deleted file mode 100644 index 94dfc245a..000000000 --- a/src/Scaffold/GeneratorCommand.php +++ /dev/null @@ -1,227 +0,0 @@ -files = new Filesystem; - } - - /** - * Execute the console command. - * - * @return bool|null - */ - public function handle() - { - $this->vars = $this->processVars($this->prepareVars()); - - $this->makeStubs(); - - $this->info($this->type . ' created successfully.'); - } - - /** - * Prepare variables for stubs. - * - * @return array - */ - abstract protected function prepareVars(); - - /** - * Make all stubs. - * - * @return void - */ - public function makeStubs() - { - $stubs = array_keys($this->stubs); - - foreach ($stubs as $stub) { - $this->makeStub($stub); - } - } - - /** - * Make a single stub. - * - * @param string $stubName The source filename for the stub. - */ - public function makeStub($stubName) - { - if (!isset($this->stubs[$stubName])) { - return; - } - - $sourceFile = $this->getSourcePath() . '/' . $stubName; - $destinationFile = $this->getDestinationPath() . '/' . $this->stubs[$stubName]; - $destinationContent = $this->files->get($sourceFile); - - /* - * Parse each variable in to the destination content and path - */ - $destinationContent = Twig::parse($destinationContent, $this->vars); - $destinationFile = Twig::parse($destinationFile, $this->vars); - - $this->makeDirectory($destinationFile); - - /* - * Make sure this file does not already exist - */ - if ($this->files->exists($destinationFile) && !$this->option('force')) { - throw new Exception('Stop everything!!! This file already exists: ' . $destinationFile); - } - - $this->files->put($destinationFile, $destinationContent); - - $this->comment('File generated: ' . str_replace(base_path(), '', $destinationFile)); - } - - /** - * 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); - } - } - - /** - * Converts all variables to available modifier and case formats. - * Syntax is CASE_MODIFIER_KEY, eg: lower_plural_xxx - * - * @param array $vars The collection of original variables - * @return array A collection of variables with modifiers added - */ - protected function processVars($vars) - { - $cases = ['upper', 'lower', 'snake', 'studly', 'camel', 'title']; - $modifiers = ['plural', 'singular', 'title']; - - foreach ($vars as $key => $var) { - /* - * Apply cases, and cases with modifiers - */ - foreach ($cases as $case) { - $primaryKey = $case . '_' . $key; - $vars[$primaryKey] = $this->modifyString($case, $var); - - foreach ($modifiers as $modifier) { - $secondaryKey = $case . '_' . $modifier . '_' . $key; - $vars[$secondaryKey] = $this->modifyString([$modifier, $case], $var); - } - } - - /* - * Apply modifiers - */ - foreach ($modifiers as $modifier) { - $primaryKey = $modifier . '_' . $key; - $vars[$primaryKey] = $this->modifyString($modifier, $var); - } - } - - return $vars; - } - - /** - * Internal helper that handles modify a string, with extra logic. - * - * @param string|array $type - * @param string $string - * @return string - */ - protected function modifyString($type, $string) - { - if (is_array($type)) { - foreach ($type as $_type) { - $string = $this->modifyString($_type, $string); - } - - return $string; - } - - if ($type == 'title') { - $string = str_replace('_', ' ', Str::snake($string)); - } - - return Str::$type($string); - } - - /** - * Get the plugin path from the input. - * - * @return string - */ - protected function getDestinationPath() - { - $plugin = $this->getPluginIdentifier(); - - $parts = explode('.', $plugin); - $name = array_pop($parts); - $author = array_pop($parts); - - return plugins_path(strtolower($author) . '/' . strtolower($name)); - } - - /** - * Get the source file path. - * - * @return string - */ - protected function getSourcePath() - { - $className = get_class($this); - $class = new ReflectionClass($className); - - return dirname($class->getFileName()); - } - - /** - * Get the desired plugin name from the input. - * - * @return string - */ - protected function getPluginIdentifier() - { - return $this->argument('plugin'); - } -} diff --git a/src/Support/aliases.php b/src/Support/aliases.php index c29f443da..dd1f69771 100644 --- a/src/Support/aliases.php +++ b/src/Support/aliases.php @@ -328,11 +328,6 @@ class_alias(\Winter\Storm\Router\RoutingServiceProvider::class, \October\Rain\Ro class_alias(\Winter\Storm\Router\Rule::class, \October\Rain\Router\Rule::class); class_alias(\Winter\Storm\Router\UrlGenerator::class, \October\Rain\Router\UrlGenerator::class); -/** - * Alias October\Rain\Scaffold - */ -class_alias(\Winter\Storm\Scaffold\GeneratorCommand::class, \October\Rain\Scaffold\GeneratorCommand::class); - /** * Alias October\Rain\Support */ diff --git a/tests/Scaffold/ScaffoldBaseTest.php b/tests/Scaffold/ScaffoldBaseTest.php index 27cf22ba3..364395b05 100644 --- a/tests/Scaffold/ScaffoldBaseTest.php +++ b/tests/Scaffold/ScaffoldBaseTest.php @@ -1,8 +1,8 @@ Date: Wed, 23 Mar 2022 14:18:25 -0600 Subject: [PATCH 2/6] Restore GeneratorCommand base class and add features from Laravel --- src/Console/GeneratorCommand.php | 326 +++++++++++++++++++++++++++++++ 1 file changed, 326 insertions(+) create mode 100644 src/Console/GeneratorCommand.php diff --git a/src/Console/GeneratorCommand.php b/src/Console/GeneratorCommand.php new file mode 100644 index 000000000..bbc60672c --- /dev/null +++ b/src/Console/GeneratorCommand.php @@ -0,0 +1,326 @@ +files = new Filesystem; + } + + /** + * Execute the console command. + * + * @return bool|null + */ + 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; + } + + $this->vars = $this->processVars($this->prepareVars()); + + $this->makeStubs(); + + $this->info($this->type . ' created successfully.'); + } + + /** + * Prepare variables for stubs. + * + * @return array + */ + abstract protected function prepareVars(); + + /** + * Make all stubs. + * + * @return void + */ + public function makeStubs() + { + $stubs = array_keys($this->stubs); + + // Make sure this command won't overwrite any existing files before running + if (!$this->option('force')) { + foreach ($stubs as $stub) { + $destinationFile = $this->getDestinationForStub($stub); + if ($this->files->exists($destinationFile)) { + throw new Exception("Cannot create the {$this->type}, $destinationFile already exists. Pass --force to overwrite existing files."); + } + } + } + + foreach ($stubs as $stub) { + $this->makeStub($stub); + } + } + + /** + * Get the destination path for the provided stub name + */ + protected function getDestinationForStub(string $stubName): string + { + return $this->getDestinationPath() . '/' . $this->stubs[$stubName]; + } + + /** + * Make a single stub. + * + * @param string $stubName The source filename for the stub. + */ + public function makeStub($stubName) + { + if (!isset($this->stubs[$stubName])) { + return; + } + + $sourceFile = $this->getSourcePath() . '/' . $stubName; + $destinationFile = $this->getDestinationForStub($stubName); + $destinationContent = $this->files->get($sourceFile); + + /* + * Parse each variable in to the destination content and path + */ + $destinationContent = Twig::parse($destinationContent, $this->vars); + $destinationFile = Twig::parse($destinationFile, $this->vars); + + $this->makeDirectory($destinationFile); + + $this->files->put($destinationFile, $destinationContent); + + $this->comment('File generated: ' . str_replace(base_path(), '', $destinationFile)); + } + + /** + * 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); + } + } + + /** + * Converts all variables to available modifier and case formats. + * Syntax is CASE_MODIFIER_KEY, eg: lower_plural_xxx + * + * @param array $vars The collection of original variables + * @return array A collection of variables with modifiers added + */ + protected function processVars($vars) + { + $cases = ['upper', 'lower', 'snake', 'studly', 'camel', 'title']; + $modifiers = ['plural', 'singular', 'title']; + + foreach ($vars as $key => $var) { + /* + * Apply cases, and cases with modifiers + */ + foreach ($cases as $case) { + $primaryKey = $case . '_' . $key; + $vars[$primaryKey] = $this->modifyString($case, $var); + + foreach ($modifiers as $modifier) { + $secondaryKey = $case . '_' . $modifier . '_' . $key; + $vars[$secondaryKey] = $this->modifyString([$modifier, $case], $var); + } + } + + /* + * Apply modifiers + */ + foreach ($modifiers as $modifier) { + $primaryKey = $modifier . '_' . $key; + $vars[$primaryKey] = $this->modifyString($modifier, $var); + } + } + + return $vars; + } + + /** + * Internal helper that handles modify a string, with extra logic. + * + * @param string|array $type + * @param string $string + * @return string + */ + protected function modifyString($type, $string) + { + if (is_array($type)) { + foreach ($type as $_type) { + $string = $this->modifyString($_type, $string); + } + + return $string; + } + + if ($type == 'title') { + $string = str_replace('_', ' ', Str::snake($string)); + } + + return Str::$type($string); + } + + /** + * Get the base path to source stub files from + */ + protected function getSourcePath(): string + { + $className = get_class($this); + $class = new ReflectionClass($className); + + return dirname($class->getFileName()); + } + + /** + * Get the base path to output generated stubs to + */ + protected function getDestinationPath(): string + { + return base_path(); + } + + /** + * Get the desired class name from the input. + */ + protected function getNameInput(): string + { + return trim($this->argument($this->nameFrom)); + } + + /** + * Checks whether the given name is reserved. + */ + protected function isReservedName(string $name): bool + { + $name = strtolower($name); + + return in_array($name, $this->reservedNames); + } +} From 43196e87b68c27ef763a4751250d1756217754c6 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Wed, 23 Mar 2022 14:27:25 -0600 Subject: [PATCH 3/6] Simplify the diff --- src/Console/GeneratorCommand.php | 16 ++++++++-------- src/Support/aliases.php | 5 +++++ tests/Scaffold/ScaffoldBaseTest.php | 4 ++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/Console/GeneratorCommand.php b/src/Console/GeneratorCommand.php index bbc60672c..628c3b972 100644 --- a/src/Console/GeneratorCommand.php +++ b/src/Console/GeneratorCommand.php @@ -287,6 +287,14 @@ protected function modifyString($type, $string) return Str::$type($string); } + /** + * Get the base path to output generated stubs to + */ + protected function getDestinationPath(): string + { + return base_path(); + } + /** * Get the base path to source stub files from */ @@ -298,14 +306,6 @@ protected function getSourcePath(): string return dirname($class->getFileName()); } - /** - * Get the base path to output generated stubs to - */ - protected function getDestinationPath(): string - { - return base_path(); - } - /** * Get the desired class name from the input. */ diff --git a/src/Support/aliases.php b/src/Support/aliases.php index dd1f69771..c29f443da 100644 --- a/src/Support/aliases.php +++ b/src/Support/aliases.php @@ -328,6 +328,11 @@ class_alias(\Winter\Storm\Router\RoutingServiceProvider::class, \October\Rain\Ro class_alias(\Winter\Storm\Router\Rule::class, \October\Rain\Router\Rule::class); class_alias(\Winter\Storm\Router\UrlGenerator::class, \October\Rain\Router\UrlGenerator::class); +/** + * Alias October\Rain\Scaffold + */ +class_alias(\Winter\Storm\Scaffold\GeneratorCommand::class, \October\Rain\Scaffold\GeneratorCommand::class); + /** * Alias October\Rain\Support */ diff --git a/tests/Scaffold/ScaffoldBaseTest.php b/tests/Scaffold/ScaffoldBaseTest.php index 364395b05..beac34887 100644 --- a/tests/Scaffold/ScaffoldBaseTest.php +++ b/tests/Scaffold/ScaffoldBaseTest.php @@ -1,8 +1,8 @@ Date: Wed, 23 Mar 2022 15:01:59 -0600 Subject: [PATCH 4/6] Fix namespace --- src/Console/GeneratorCommand.php | 16 ++++------------ src/Support/aliases.php | 3 ++- tests/Scaffold/ScaffoldBaseTest.php | 2 +- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/Console/GeneratorCommand.php b/src/Console/GeneratorCommand.php index 628c3b972..9c03f5769 100644 --- a/src/Console/GeneratorCommand.php +++ b/src/Console/GeneratorCommand.php @@ -1,9 +1,8 @@ -stubs); @@ -228,11 +223,8 @@ protected function makeDirectory($path) /** * Converts all variables to available modifier and case formats. * Syntax is CASE_MODIFIER_KEY, eg: lower_plural_xxx - * - * @param array $vars The collection of original variables - * @return array A collection of variables with modifiers added */ - protected function processVars($vars) + protected function processVars(array $vars): array { $cases = ['upper', 'lower', 'snake', 'studly', 'camel', 'title']; $modifiers = ['plural', 'singular', 'title']; diff --git a/src/Support/aliases.php b/src/Support/aliases.php index c29f443da..0259ef2df 100644 --- a/src/Support/aliases.php +++ b/src/Support/aliases.php @@ -331,7 +331,8 @@ class_alias(\Winter\Storm\Router\UrlGenerator::class, \October\Rain\Router\UrlGe /** * Alias October\Rain\Scaffold */ -class_alias(\Winter\Storm\Scaffold\GeneratorCommand::class, \October\Rain\Scaffold\GeneratorCommand::class); +class_alias(\Winter\Storm\Console\GeneratorCommand::class, \October\Rain\Scaffold\GeneratorCommand::class); +class_alias(\Winter\Storm\Console\GeneratorCommand::class, \Winter\Storm\Scaffold\GeneratorCommand::class); /** * Alias October\Rain\Support diff --git a/tests/Scaffold/ScaffoldBaseTest.php b/tests/Scaffold/ScaffoldBaseTest.php index beac34887..ab29df544 100644 --- a/tests/Scaffold/ScaffoldBaseTest.php +++ b/tests/Scaffold/ScaffoldBaseTest.php @@ -1,6 +1,6 @@ Date: Sun, 3 Apr 2022 13:35:42 -0600 Subject: [PATCH 5/6] fix tests --- tests/Scaffold/ScaffoldBaseTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Scaffold/ScaffoldBaseTest.php b/tests/Scaffold/ScaffoldBaseTest.php index ab29df544..75edb4eae 100644 --- a/tests/Scaffold/ScaffoldBaseTest.php +++ b/tests/Scaffold/ScaffoldBaseTest.php @@ -8,7 +8,7 @@ public function __construct() { } - protected function prepareVars() + protected function prepareVars(): array { return []; } From ab316c7bf828e5c3d2f5b5d605c0f62d976ac58d Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sun, 3 Apr 2022 13:40:04 -0600 Subject: [PATCH 6/6] Move GeneratorCommand back to Scaffold --- src/{Console => Scaffold}/GeneratorCommand.php | 3 ++- src/Support/aliases.php | 3 +-- tests/Scaffold/ScaffoldBaseTest.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/{Console => Scaffold}/GeneratorCommand.php (99%) diff --git a/src/Console/GeneratorCommand.php b/src/Scaffold/GeneratorCommand.php similarity index 99% rename from src/Console/GeneratorCommand.php rename to src/Scaffold/GeneratorCommand.php index 9c03f5769..71d9d844b 100644 --- a/src/Console/GeneratorCommand.php +++ b/src/Scaffold/GeneratorCommand.php @@ -1,8 +1,9 @@ -