From b437f45dbf550b8ad633bea04a4393733617c5a0 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Mon, 14 Nov 2022 22:34:03 -0600 Subject: [PATCH 1/5] make:cell command and refactored GeneratorTrait. --- system/CLI/GeneratorTrait.php | 71 ++++++++---- system/Commands/Generators/CellGenerator.php | 102 ++++++++++++++++++ system/Commands/Generators/Views/cell.tpl.php | 10 ++ .../Generators/Views/cell_view.tpl.php | 3 + tests/system/Commands/CellGeneratorTest.php | 92 ++++++++++++++++ user_guide_src/source/outgoing/view_cells.rst | 9 ++ 6 files changed, 269 insertions(+), 18 deletions(-) create mode 100644 system/Commands/Generators/CellGenerator.php create mode 100644 system/Commands/Generators/Views/cell.tpl.php create mode 100644 system/Commands/Generators/Views/cell_view.tpl.php create mode 100644 tests/system/Commands/CellGeneratorTest.php diff --git a/system/CLI/GeneratorTrait.php b/system/CLI/GeneratorTrait.php index e1452f3be814..97f011f80ca6 100644 --- a/system/CLI/GeneratorTrait.php +++ b/system/CLI/GeneratorTrait.php @@ -86,11 +86,57 @@ trait GeneratorTrait /** * Execute the command. + * + * @deprecated use generateClass() instead */ protected function execute(array $params): void + { + $this->generateClass($params); + } + + /** + * Generates a class file from an existing template. + */ + protected function generateClass(array $params) { $this->params = $params; + // Get the fully qualified class name from the input. + $class = $this->qualifyClassName(); + + // Get the file path from class name. + $target = $this->buildPath($class); + + // Check if path is empty. + if (empty($target)) { + return; + } + + $this->generateFile($target, $this->buildContent($class)); + } + + /** + * Generate a view file from an existing template. + */ + protected function generateView(string $view, array $params) + { + $this->params = $params; + + $target = $this->buildPath($view); + + // Check if path is empty. + if (empty($target)) { + return; + } + + $this->generateFile($target, $this->buildContent($view)); + } + + /** + * Handles writing the file to disk, and all of the safety checks around that. + */ + private function generateFile(string $target, string $content): void + { if ($this->getOption('namespace') === 'CodeIgniter') { // @codeCoverageIgnoreStart CLI::write(lang('CLI.generator.usingCINamespace'), 'yellow'); @@ -108,30 +154,19 @@ protected function execute(array $params): void // @codeCoverageIgnoreEnd } - // Get the fully qualified class name from the input. - $class = $this->qualifyClassName(); - - // Get the file path from class name. - $path = $this->buildPath($class); - - // Check if path is empty. - if (empty($path)) { - return; - } - - $isFile = is_file($path); + $isFile = is_file($target); // 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($path)]), 'light_gray', 'red'); + CLI::error(lang('CLI.generator.fileExist', [clean_path($target)]), 'light_gray', 'red'); CLI::newLine(); return; } // Check if the directory to save the file is existing. - $dir = dirname($path); + $dir = dirname($target); if (! is_dir($dir)) { mkdir($dir, 0755, true); @@ -141,9 +176,9 @@ protected function execute(array $params): void // Build the class based on the details we have, We'll be getting our file // contents from the template, and then we'll do the necessary replacements. - if (! write_file($path, $this->buildContent($class))) { + if (! write_file($target, $content)) { // @codeCoverageIgnoreStart - CLI::error(lang('CLI.generator.fileError', [clean_path($path)]), 'light_gray', 'red'); + CLI::error(lang('CLI.generator.fileError', [clean_path($target)]), 'light_gray', 'red'); CLI::newLine(); return; @@ -151,13 +186,13 @@ protected function execute(array $params): void } if ($this->getOption('force') && $isFile) { - CLI::write(lang('CLI.generator.fileOverwrite', [clean_path($path)]), 'yellow'); + CLI::write(lang('CLI.generator.fileOverwrite', [clean_path($target)]), 'yellow'); CLI::newLine(); return; } - CLI::write(lang('CLI.generator.fileCreate', [clean_path($path)]), 'green'); + CLI::write(lang('CLI.generator.fileCreate', [clean_path($target)]), 'green'); CLI::newLine(); } diff --git a/system/Commands/Generators/CellGenerator.php b/system/Commands/Generators/CellGenerator.php new file mode 100644 index 000000000000..3fd8a0cd67df --- /dev/null +++ b/system/Commands/Generators/CellGenerator.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Commands\Generators; + +use CodeIgniter\CLI\BaseCommand; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a skeleton Cell and its view. + */ +class CellGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:cell'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a new Cell file and its view.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:cell [options]'; + + /** + * The Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'name' => 'The entity class name.', + ]; + + /** + * The Command's Options + * + * @var array + */ + protected $options = [ + '--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".', + '--suffix' => 'Append the component title to the class name (e.g. User => UserCell).', + '--force' => 'Force overwrite existing file.', + ]; + + /** + * Actually execute a command. + */ + public function run(array $params) + { + // Generate the Class first + $this->component = 'Cell'; + $this->directory = 'Cells'; + $this->template = 'cell.tpl.php'; + $this->classNameLang = 'CLI.generator.className.cell'; + + $this->generateClass($params); + + // Generate the View + + // Form the view name + $segments = explode('\\', $this->qualifyClassName()); + + $view = array_pop($segments); + $view = str_replace('Cell', '', decamelize($view)); + if (strpos($view, '_cell') === false) { + $view .= '_cell'; + } + $segments[] = $view; + $view = implode('\\', $segments); + + $this->template = 'cell_view.tpl.php'; + + $this->generateView($view, $params); + } +} diff --git a/system/Commands/Generators/Views/cell.tpl.php b/system/Commands/Generators/Views/cell.tpl.php new file mode 100644 index 000000000000..f20c07851d7a --- /dev/null +++ b/system/Commands/Generators/Views/cell.tpl.php @@ -0,0 +1,10 @@ +<@php + +namespace {namespace}; + +use CodeIgniter\View\Cells\Cell; + +class {class} extends Cell +{ + // +} diff --git a/system/Commands/Generators/Views/cell_view.tpl.php b/system/Commands/Generators/Views/cell_view.tpl.php new file mode 100644 index 000000000000..9866dc2e889e --- /dev/null +++ b/system/Commands/Generators/Views/cell_view.tpl.php @@ -0,0 +1,3 @@ +
+ +
diff --git a/tests/system/Commands/CellGeneratorTest.php b/tests/system/Commands/CellGeneratorTest.php new file mode 100644 index 000000000000..9abb022ad4d7 --- /dev/null +++ b/tests/system/Commands/CellGeneratorTest.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Commands; + +use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\StreamFilterTrait; + +/** + * @internal + */ +final class CellGeneratorTest extends CIUnitTestCase +{ + use StreamFilterTrait; + + protected function tearDown(): void + { + $dirName = APPPATH . DIRECTORY_SEPARATOR . 'Cells'; + // remove dir + if (is_dir($dirName)) { + $files = array_diff(scandir($dirName), ['.', '..']); + + foreach ($files as $file) { + (is_dir("{$dirName}/{$file}")) ? rmdir("{$dirName}/{$file}") : unlink("{$dirName}/{$file}"); + } + rmdir($dirName); + } + } + + protected function getFileContents(string $filepath): string + { + if (! is_file($filepath)) { + return ''; + } + + return file_get_contents($filepath) ?: ''; + } + + public function testGenerateCell() + { + command('make:cell RecentCell'); + + // Check the class was generated + $file = APPPATH . 'Cells/RecentCell.php'; + $this->assertFileExists($file); + $contents = $this->getFileContents($file); + $this->assertStringContainsString('class RecentCell extends Cell', $contents); + + // Check the view was generated + $file = APPPATH . 'Cells/recent_cell.php'; + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); + $this->assertFileExists(APPPATH . 'Cells/recent_cell.php'); + } + + public function testGenerateCellSimpleName() + { + command('make:cell Another'); + + // Check the class was generated + $file = APPPATH . 'Cells/Another.php'; + $this->assertFileExists($file); + $contents = $this->getFileContents($file); + $this->assertStringContainsString('class Another extends Cell', $contents); + + // Check the view was generated + $file = APPPATH . 'Cells/another_cell.php'; + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); + $this->assertFileExists(APPPATH . 'Cells/another_cell.php'); + } + + private function cleanUp() + { + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + $dir = dirname($file); + + if (is_file($file)) { + unlink($file); + } + if (is_dir($dir) && strpos($dir, 'Cells') !== false) { + rmdir($dir); + } + } +} diff --git a/user_guide_src/source/outgoing/view_cells.rst b/user_guide_src/source/outgoing/view_cells.rst index 39a87ee86c7b..5b8975c963fc 100644 --- a/user_guide_src/source/outgoing/view_cells.rst +++ b/user_guide_src/source/outgoing/view_cells.rst @@ -98,6 +98,15 @@ At the most basic level, all you need to implement within the class are public p +Generating Cell via Command +=========================== + +You can also create a controlled cell via a built in command from the CLI. The command is ``php spark make:cell``. It takes one argument, the name of the cell to create. The name should be in PascalCase, and the class will be created in the ``app/Cells`` directory. The view file will also be created in the ``app/Views/cells`` directory. + +```console +php spark make:cell AlertMessage +``` + Using a Different View ====================== From 23d1579fa5759cfe28367101e149035ce3d2071d Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Mon, 14 Nov 2022 22:48:17 -0600 Subject: [PATCH 2/5] Adding tests to groups --- tests/system/Commands/CellGeneratorTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/system/Commands/CellGeneratorTest.php b/tests/system/Commands/CellGeneratorTest.php index 9abb022ad4d7..dc1bea8ef383 100644 --- a/tests/system/Commands/CellGeneratorTest.php +++ b/tests/system/Commands/CellGeneratorTest.php @@ -44,6 +44,9 @@ protected function getFileContents(string $filepath): string return file_get_contents($filepath) ?: ''; } + /** + * @group Others + */ public function testGenerateCell() { command('make:cell RecentCell'); @@ -60,6 +63,9 @@ public function testGenerateCell() $this->assertFileExists(APPPATH . 'Cells/recent_cell.php'); } + /** + * @group Others + */ public function testGenerateCellSimpleName() { command('make:cell Another'); From b531b62b94606f58cb218f03fa03ecf6795ac60d Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Tue, 15 Nov 2022 23:01:49 -0600 Subject: [PATCH 3/5] Update tests/system/Commands/CellGeneratorTest.php Co-authored-by: John Paul E. Balandan, CPA --- tests/system/Commands/CellGeneratorTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/system/Commands/CellGeneratorTest.php b/tests/system/Commands/CellGeneratorTest.php index dc1bea8ef383..e81ffe9c42a9 100644 --- a/tests/system/Commands/CellGeneratorTest.php +++ b/tests/system/Commands/CellGeneratorTest.php @@ -16,6 +16,8 @@ /** * @internal + * + * @group Others */ final class CellGeneratorTest extends CIUnitTestCase { From 323c245a32b7a8d05abc166a8357ebaaa545c698 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Wed, 16 Nov 2022 22:01:34 -0600 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Denny Septian Panggabean <97607754+ddevsr@users.noreply.github.com> --- tests/system/Commands/CellGeneratorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Commands/CellGeneratorTest.php b/tests/system/Commands/CellGeneratorTest.php index e81ffe9c42a9..4cd1151197d1 100644 --- a/tests/system/Commands/CellGeneratorTest.php +++ b/tests/system/Commands/CellGeneratorTest.php @@ -62,7 +62,7 @@ public function testGenerateCell() // Check the view was generated $file = APPPATH . 'Cells/recent_cell.php'; $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); - $this->assertFileExists(APPPATH . 'Cells/recent_cell.php'); + $this->assertFileExists($file); } /** @@ -81,7 +81,7 @@ public function testGenerateCellSimpleName() // Check the view was generated $file = APPPATH . 'Cells/another_cell.php'; $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); - $this->assertFileExists(APPPATH . 'Cells/another_cell.php'); + $this->assertFileExists($file); } private function cleanUp() From 3778c8805406f6c1ef2b058b063e98e676a1cc85 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Wed, 16 Nov 2022 22:19:53 -0600 Subject: [PATCH 5/5] Remove unnecessary code --- tests/system/Commands/CellGeneratorTest.php | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/tests/system/Commands/CellGeneratorTest.php b/tests/system/Commands/CellGeneratorTest.php index 4cd1151197d1..35b119606515 100644 --- a/tests/system/Commands/CellGeneratorTest.php +++ b/tests/system/Commands/CellGeneratorTest.php @@ -46,9 +46,6 @@ protected function getFileContents(string $filepath): string return file_get_contents($filepath) ?: ''; } - /** - * @group Others - */ public function testGenerateCell() { command('make:cell RecentCell'); @@ -65,9 +62,6 @@ public function testGenerateCell() $this->assertFileExists($file); } - /** - * @group Others - */ public function testGenerateCellSimpleName() { command('make:cell Another'); @@ -83,18 +77,4 @@ public function testGenerateCellSimpleName() $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists($file); } - - private function cleanUp() - { - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); - $dir = dirname($file); - - if (is_file($file)) { - unlink($file); - } - if (is_dir($dir) && strpos($dir, 'Cells') !== false) { - rmdir($dir); - } - } }