diff --git a/app/Config/Generators.php b/app/Config/Generators.php index 6566a31e851e..cc92c7aa432f 100644 --- a/app/Config/Generators.php +++ b/app/Config/Generators.php @@ -23,11 +23,13 @@ class Generators extends BaseConfig * * YOU HAVE BEEN WARNED! * - * @var array + * @var array|string> */ public array $views = [ - 'make:cell' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php', - 'make:cell_view' => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php', + 'make:cell' => [ + 'class' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php', + 'view' => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php', + ], 'make:command' => 'CodeIgniter\Commands\Generators\Views\command.tpl.php', 'make:config' => 'CodeIgniter\Commands\Generators\Views\config.tpl.php', 'make:controller' => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php', diff --git a/system/CLI/GeneratorTrait.php b/system/CLI/GeneratorTrait.php index 7b6066380739..c1112ca63481 100644 --- a/system/CLI/GeneratorTrait.php +++ b/system/CLI/GeneratorTrait.php @@ -36,7 +36,15 @@ trait GeneratorTrait protected $directory; /** - * View template name + * (Optional) View template path + * + * We use special namespaced paths like: + * `CodeIgniter\Commands\Generators\Views\cell.tpl.php`. + */ + protected ?string $templatePath = null; + + /** + * View template name for fallback * * @var string */ @@ -118,6 +126,8 @@ protected function generateClass(array $params) /** * Generate a view file from an existing template. + * + * @param string $view namespaced view name that is generated */ protected function generateView(string $view, array $params) { @@ -135,6 +145,8 @@ protected function generateView(string $view, array $params) /** * Handles writing the file to disk, and all of the safety checks around that. + * + * @param string $target file path */ private function generateFile(string $target, string $content): void { @@ -143,7 +155,13 @@ private function generateFile(string $target, string $content): void CLI::write(lang('CLI.generator.usingCINamespace'), 'yellow'); CLI::newLine(); - if (CLI::prompt('Are you sure you want to continue?', ['y', 'n'], 'required') === 'n') { + if ( + CLI::prompt( + 'Are you sure you want to continue?', + ['y', 'n'], + 'required' + ) === 'n' + ) { CLI::newLine(); CLI::write(lang('CLI.generator.cancelOperation'), 'yellow'); CLI::newLine(); @@ -160,7 +178,11 @@ private function generateFile(string $target, string $content): void // Overwriting files unknowingly is a serious annoyance, So we'll check if // we are duplicating things, If 'force' option is not supplied, we bail. if (! $this->getOption('force') && $isFile) { - CLI::error(lang('CLI.generator.fileExist', [clean_path($target)]), 'light_gray', 'red'); + CLI::error( + lang('CLI.generator.fileExist', [clean_path($target)]), + 'light_gray', + 'red' + ); CLI::newLine(); return; @@ -179,7 +201,11 @@ private function generateFile(string $target, string $content): void // contents from the template, and then we'll do the necessary replacements. if (! write_file($target, $content)) { // @codeCoverageIgnoreStart - CLI::error(lang('CLI.generator.fileError', [clean_path($target)]), 'light_gray', 'red'); + CLI::error( + lang('CLI.generator.fileError', [clean_path($target)]), + 'light_gray', + 'red' + ); CLI::newLine(); return; @@ -187,18 +213,28 @@ private function generateFile(string $target, string $content): void } if ($this->getOption('force') && $isFile) { - CLI::write(lang('CLI.generator.fileOverwrite', [clean_path($target)]), 'yellow'); + CLI::write( + lang('CLI.generator.fileOverwrite', [clean_path($target)]), + 'yellow' + ); CLI::newLine(); return; } - CLI::write(lang('CLI.generator.fileCreate', [clean_path($target)]), 'green'); + CLI::write( + lang('CLI.generator.fileCreate', [clean_path($target)]), + 'green' + ); CLI::newLine(); } /** * Prepare options and do the necessary replacements. + * + * @param string $class namespaced classname or namespaced view. + * + * @return string generated file content */ protected function prepare(string $class): string { @@ -244,15 +280,34 @@ protected function qualifyClassName(): string $class = $matches[1] . ucfirst($matches[2]); } - if ($this->enabledSuffixing && $this->getOption('suffix') && preg_match($pattern, $class) !== 1) { + if ( + $this->enabledSuffixing && $this->getOption('suffix') + && preg_match($pattern, $class) !== 1 + ) { $class .= ucfirst($component); } // Trims input, normalize separators, and ensure that all paths are in Pascalcase. - $class = ltrim(implode('\\', array_map('pascalize', explode('\\', str_replace('/', '\\', trim($class))))), '\\/'); + $class = ltrim( + implode( + '\\', + array_map( + 'pascalize', + explode('\\', str_replace('/', '\\', trim($class))) + ) + ), + '\\/' + ); // Gets the namespace from input. Don't forget the ending backslash! - $namespace = trim(str_replace('/', '\\', $this->getOption('namespace') ?? APP_NAMESPACE), '\\') . '\\'; + $namespace = trim( + str_replace( + '/', + '\\', + $this->getOption('namespace') ?? APP_NAMESPACE + ), + '\\' + ) . '\\'; if (strncmp($class, $namespace, strlen($namespace)) === 0) { return $class; // @codeCoverageIgnore @@ -268,21 +323,41 @@ protected function qualifyClassName(): string protected function renderTemplate(array $data = []): string { try { - return view(config(Generators::class)->views[$this->name], $data, ['debug' => false]); + $template = $this->templatePath ?? config(Generators::class)->views[$this->name]; + + return view($template, $data, ['debug' => false]); } catch (Throwable $e) { log_message('error', (string) $e); - return view("CodeIgniter\\Commands\\Generators\\Views\\{$this->template}", $data, ['debug' => false]); + return view( + "CodeIgniter\\Commands\\Generators\\Views\\{$this->template}", + $data, + ['debug' => false] + ); } } /** * Performs pseudo-variables contained within view file. + * + * @param string $class namespaced classname or namespaced view. + * + * @return string generated file content */ - protected function parseTemplate(string $class, array $search = [], array $replace = [], array $data = []): string - { + protected function parseTemplate( + string $class, + array $search = [], + array $replace = [], + array $data = [] + ): string { // Retrieves the namespace part from the fully qualified class name. - $namespace = trim(implode('\\', array_slice(explode('\\', $class), 0, -1)), '\\'); + $namespace = trim( + implode( + '\\', + array_slice(explode('\\', $class), 0, -1) + ), + '\\' + ); $search[] = '<@php'; $search[] = '{namespace}'; $search[] = '{class}'; @@ -302,7 +377,14 @@ protected function buildContent(string $class): string { $template = $this->prepare($class); - if ($this->sortImports && preg_match('/(?P(?:^use [^;]+;$\n?)+)/m', $template, $match)) { + if ( + $this->sortImports + && preg_match( + '/(?P(?:^use [^;]+;$\n?)+)/m', + $template, + $match + ) + ) { $imports = explode("\n", trim($match['imports'])); sort($imports); @@ -314,25 +396,50 @@ protected function buildContent(string $class): string /** * Builds the file path from the class name. + * + * @param string $class namespaced classname or namespaced view. */ protected function buildPath(string $class): string { - $namespace = trim(str_replace('/', '\\', $this->getOption('namespace') ?? APP_NAMESPACE), '\\'); + $namespace = trim( + str_replace( + '/', + '\\', + $this->getOption('namespace') ?? APP_NAMESPACE + ), + '\\' + ); // Check if the namespace is actually defined and we are not just typing gibberish. $base = Services::autoloader()->getNamespace($namespace); if (! $base = reset($base)) { - CLI::error(lang('CLI.namespaceNotDefined', [$namespace]), 'light_gray', 'red'); + CLI::error( + lang('CLI.namespaceNotDefined', [$namespace]), + 'light_gray', + 'red' + ); CLI::newLine(); return ''; } $base = realpath($base) ?: $base; - $file = $base . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, trim(str_replace($namespace . '\\', '', $class), '\\')) . '.php'; - - return implode(DIRECTORY_SEPARATOR, array_slice(explode(DIRECTORY_SEPARATOR, $file), 0, -1)) . DIRECTORY_SEPARATOR . $this->basename($file); + $file = $base . DIRECTORY_SEPARATOR + . str_replace( + '\\', + DIRECTORY_SEPARATOR, + trim(str_replace($namespace . '\\', '', $class), '\\') + ) . '.php'; + + return implode( + DIRECTORY_SEPARATOR, + array_slice( + explode(DIRECTORY_SEPARATOR, $file), + 0, + -1 + ) + ) . DIRECTORY_SEPARATOR . $this->basename($file); } /** diff --git a/system/Commands/Generators/CellGenerator.php b/system/Commands/Generators/CellGenerator.php index cf4757d10eeb..78f012ec10c7 100644 --- a/system/Commands/Generators/CellGenerator.php +++ b/system/Commands/Generators/CellGenerator.php @@ -13,6 +13,7 @@ use CodeIgniter\CLI\BaseCommand; use CodeIgniter\CLI\GeneratorTrait; +use Config\Generators; /** * Generates a skeleton Cell and its view. @@ -78,17 +79,23 @@ public function run(array $params) $params = array_merge($params, ['suffix' => null]); + $this->templatePath = config(Generators::class)->views[$this->name]['class']; $this->template = 'cell.tpl.php'; $this->classNameLang = 'CLI.generator.className.cell'; + $this->generateClass($params); - $this->name = 'make:cell_view'; + $this->templatePath = config(Generators::class)->views[$this->name]['view']; $this->template = 'cell_view.tpl.php'; $this->classNameLang = 'CLI.generator.viewName.cell'; $className = $this->qualifyClassName(); $viewName = decamelize(class_basename($className)); - $viewName = preg_replace('/([a-z][a-z0-9_\/\\\\]+)(_cell)$/i', '$1', $viewName) ?? $viewName; + $viewName = preg_replace( + '/([a-z][a-z0-9_\/\\\\]+)(_cell)$/i', + '$1', + $viewName + ) ?? $viewName; $namespace = substr($className, 0, strrpos($className, '\\') + 1); $this->generateView($namespace . $viewName, $params); diff --git a/system/Commands/Generators/CommandGenerator.php b/system/Commands/Generators/CommandGenerator.php index b844666a794e..3a47e68ac786 100644 --- a/system/Commands/Generators/CommandGenerator.php +++ b/system/Commands/Generators/CommandGenerator.php @@ -83,7 +83,7 @@ public function run(array $params) $this->template = 'command.tpl.php'; $this->classNameLang = 'CLI.generator.className.command'; - $this->execute($params); + $this->generateClass($params); } /** diff --git a/system/Commands/Generators/ConfigGenerator.php b/system/Commands/Generators/ConfigGenerator.php index a83a9671201d..217c00be46c0 100644 --- a/system/Commands/Generators/ConfigGenerator.php +++ b/system/Commands/Generators/ConfigGenerator.php @@ -79,7 +79,7 @@ public function run(array $params) $this->template = 'config.tpl.php'; $this->classNameLang = 'CLI.generator.className.config'; - $this->execute($params); + $this->generateClass($params); } /** diff --git a/system/Commands/Generators/ControllerGenerator.php b/system/Commands/Generators/ControllerGenerator.php index 2cf912b1c7ff..869bd5d15e82 100644 --- a/system/Commands/Generators/ControllerGenerator.php +++ b/system/Commands/Generators/ControllerGenerator.php @@ -85,7 +85,7 @@ public function run(array $params) $this->template = 'controller.tpl.php'; $this->classNameLang = 'CLI.generator.className.controller'; - $this->execute($params); + $this->generateClass($params); } /** diff --git a/system/Commands/Generators/EntityGenerator.php b/system/Commands/Generators/EntityGenerator.php index bd20daf59662..4cb44ad32d48 100644 --- a/system/Commands/Generators/EntityGenerator.php +++ b/system/Commands/Generators/EntityGenerator.php @@ -79,6 +79,6 @@ public function run(array $params) $this->template = 'entity.tpl.php'; $this->classNameLang = 'CLI.generator.className.entity'; - $this->execute($params); + $this->generateClass($params); } } diff --git a/system/Commands/Generators/FilterGenerator.php b/system/Commands/Generators/FilterGenerator.php index 620bee5a9ad4..ad1fa2da6908 100644 --- a/system/Commands/Generators/FilterGenerator.php +++ b/system/Commands/Generators/FilterGenerator.php @@ -79,6 +79,6 @@ public function run(array $params) $this->template = 'filter.tpl.php'; $this->classNameLang = 'CLI.generator.className.filter'; - $this->execute($params); + $this->generateClass($params); } } diff --git a/system/Commands/Generators/MigrationGenerator.php b/system/Commands/Generators/MigrationGenerator.php index 52f9e6e53535..de648d130c2c 100644 --- a/system/Commands/Generators/MigrationGenerator.php +++ b/system/Commands/Generators/MigrationGenerator.php @@ -90,7 +90,7 @@ public function run(array $params) } $this->classNameLang = 'CLI.generator.className.migration'; - $this->execute($params); + $this->generateClass($params); } /** diff --git a/system/Commands/Generators/ModelGenerator.php b/system/Commands/Generators/ModelGenerator.php index f4946a9441c9..6a817ef50eb5 100644 --- a/system/Commands/Generators/ModelGenerator.php +++ b/system/Commands/Generators/ModelGenerator.php @@ -83,7 +83,7 @@ public function run(array $params) $this->template = 'model.tpl.php'; $this->classNameLang = 'CLI.generator.className.model'; - $this->execute($params); + $this->generateClass($params); } /** diff --git a/system/Commands/Generators/SeederGenerator.php b/system/Commands/Generators/SeederGenerator.php index e60525ae0d57..b4a6d76ad4ce 100644 --- a/system/Commands/Generators/SeederGenerator.php +++ b/system/Commands/Generators/SeederGenerator.php @@ -79,6 +79,6 @@ public function run(array $params) $this->template = 'seeder.tpl.php'; $this->classNameLang = 'CLI.generator.className.seeder'; - $this->execute($params); + $this->generateClass($params); } } diff --git a/system/Commands/Generators/ValidationGenerator.php b/system/Commands/Generators/ValidationGenerator.php index 1b2efb8db18a..0a116f071682 100644 --- a/system/Commands/Generators/ValidationGenerator.php +++ b/system/Commands/Generators/ValidationGenerator.php @@ -79,6 +79,6 @@ public function run(array $params) $this->template = 'validation.tpl.php'; $this->classNameLang = 'CLI.generator.className.validation'; - $this->execute($params); + $this->generateClass($params); } } diff --git a/tests/_support/Commands/LanguageCommand.php b/tests/_support/Commands/LanguageCommand.php index 978099e5257f..172774c43477 100644 --- a/tests/_support/Commands/LanguageCommand.php +++ b/tests/_support/Commands/LanguageCommand.php @@ -39,7 +39,7 @@ public function run(array $params): void $sort = (isset($params['sort']) && $params['sort'] === 'off') ? false : true; $this->setSortImports($sort); - $this->execute($params); + $this->generateClass($params); } protected function prepare(string $class): string diff --git a/tests/_support/Commands/Unsuffixable.php b/tests/_support/Commands/Unsuffixable.php index 087dc558fdc0..96bfcb5d8205 100644 --- a/tests/_support/Commands/Unsuffixable.php +++ b/tests/_support/Commands/Unsuffixable.php @@ -72,6 +72,6 @@ public function run(array $params): void $this->template = 'command.tpl.php'; $this->setEnabledSuffixing(false); - $this->execute($params); + $this->generateClass($params); } }