diff --git a/app/Config/Generators.php b/app/Config/Generators.php index 5ea633e5a954..301e889b377a 100644 --- a/app/Config/Generators.php +++ b/app/Config/Generators.php @@ -26,13 +26,13 @@ class Generators extends BaseConfig * @var array */ public $views = [ - 'make:command' => 'CodeIgniter\\Commands\\Generators\\Views\\command.tpl.php', - 'make:controller' => 'CodeIgniter\\Commands\\Generators\\Views\\controller.tpl.php', - 'make:entity' => 'CodeIgniter\\Commands\\Generators\\Views\\entity.tpl.php', - 'make:filter' => 'CodeIgniter\\Commands\\Generators\\Views\\filter.tpl.php', - 'make:migration' => 'CodeIgniter\\Commands\\Generators\\Views\\migration.tpl.php', - 'make:model' => 'CodeIgniter\\Commands\\Generators\\Views\\model.tpl.php', - 'make:seeder' => 'CodeIgniter\\Commands\\Generators\\Views\\seed.tpl.php', - 'session:migration' => 'CodeIgniter\\Commands\\Generators\\Views\\session_migration.tpl.php', + 'make:command' => 'CodeIgniter\Commands\Generators\Views\command.tpl.php', + 'make:controller' => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php', + 'make:entity' => 'CodeIgniter\Commands\Generators\Views\entity.tpl.php', + 'make:filter' => 'CodeIgniter\Commands\Generators\Views\filter.tpl.php', + 'make:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php', + 'make:model' => 'CodeIgniter\Commands\Generators\Views\model.tpl.php', + 'make:seeder' => 'CodeIgniter\Commands\Generators\Views\seeder.tpl.php', + 'session:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php', ]; } diff --git a/system/CLI/GeneratorCommand.php b/system/CLI/GeneratorCommand.php deleted file mode 100644 index 7c7042ef7355..000000000000 --- a/system/CLI/GeneratorCommand.php +++ /dev/null @@ -1,371 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace CodeIgniter\CLI; - -use Config\Generators; -use Config\Services; -use Psr\Log\LoggerInterface; -use RuntimeException; -use Throwable; - -/** - * GeneratorCommand can be used as base class - * for creating commands that generates a file. - */ -abstract class GeneratorCommand extends BaseCommand -{ - /** - * The group the command is lumped under - * when listing commands. - * - * @var string - */ - protected $group = 'Generators'; - - /** - * Default arguments. - * - * @var array - */ - private $defaultArguments = [ - 'name' => 'Class name', - ]; - - /** - * Default option set. - * - * @var array - */ - private $defaultOptions = [ - '-n' => 'Set root namespace. Defaults to APP_NAMESPACE.', - '--force' => 'Force overwrite existing files.', - ]; - - /** - * Whether to sort class imports. - * - * @internal - * - * @var boolean - */ - private $sortImports = true; - - /** - * The params array for easy access by other methods. - * - * @var array - */ - protected $params = []; - - /** - * Instance of Config\Generators - * - * @var Generators - */ - protected $config; - - /** - * Constructor. - * - * @param LoggerInterface $logger - * @param Commands $commands - */ - public function __construct(LoggerInterface $logger, Commands $commands) - { - $this->arguments = array_merge($this->defaultArguments, $this->arguments); - $this->options = array_merge($this->options, $this->defaultOptions); - $this->config = config('Config\Generators'); - - parent::__construct($logger, $commands); - } - - /** - * Actually execute a command. - * - * @param array $params - */ - public function run(array $params) - { - $this->params = $params; - - // First, we'll get the fully qualified class name from the input, - // pascalizing it if not yet done. Then we will try to get the file - // path from this. - helper('inflector'); - $class = $this->qualifyClassName($this->sanitizeClassName($this->getClassName())); - $path = $this->buildPath($class); - - // Next, overwriting files unknowingly is a serious annoyance. So we'll check - // if we are duplicating things. If the 'force' option is not supplied, we bail. - if (! (array_key_exists('force', $params) || CLI::getOption('force')) && file_exists($path)) - { - CLI::error(lang('CLI.generateFileExists', [clean_path($path)]), 'light_gray', 'red'); - CLI::newLine(); - - return; - } - - // Next, check if the directory to save the file is existing. - $dir = dirname($path); - - if (! is_dir($dir)) - { - mkdir($dir, 0755, true); - } - - // Lastly, we'll build the class based on the details we have. We'll be getting our - // file contents from a template and then we'll do the necessary replacements. - helper('filesystem'); - if (! write_file($path, $this->sortImports($this->buildClassContents($class)))) - { - CLI::error(lang('CLI.generateFileError') . clean_path($path), 'light_gray', 'red'); - CLI::newLine(); - - return; - } - - CLI::write(lang('CLI.generateFileSuccess') . CLI::color(clean_path($path), 'green')); - CLI::newLine(); - } - - /** - * Allows child generators to modify - * the internal `$sortImports` flag. - * - * @param boolean $sort - * - * @return $this - */ - protected function setSortImports(bool $sort) - { - $this->sortImports = $sort; - - return $this; - } - - /** - * Gets the class name from input. This can be overridden - * if name is really required by providing a prompt. - * - * @return string - */ - protected function getClassName(): string - { - $name = $this->params[0] ?? CLI::getSegment(2); - - return $name ?? ''; - } - - /** - * Trims input, normalize separators, and ensures - * all paths are in Pascal case. - * - * @param string $class - * - * @return string - */ - protected function sanitizeClassName(string $class): string - { - $class = trim($class); - $class = str_replace('/', '\\', $class); - - return implode('\\', array_map('pascalize', explode('\\', $class))); - } - - /** - * Parses the class name and checks if it is already qualified. - * - * @param string $class - * - * @return string - */ - protected function qualifyClassName(string $class): string - { - $class = ltrim($class, '\\/'); - $rootNS = $this->getRootNamespace(); - - if (strncmp($class, $rootNS, strlen($rootNS)) === 0) - { - return $class; - } - - $class = str_replace('/', '\\', $class); - - return $this->qualifyClassName($this->getNamespacedClass($rootNS, $class)); - } - - /** - * Gets the root namespace from input. - * - * @return string - */ - protected function getRootNamespace(): string - { - $rootNamespace = $this->params['n'] ?? CLI::getOption('n') ?? APP_NAMESPACE; - - return trim(str_replace('/', '\\', $rootNamespace), '\\'); - } - - /** - * Gets the qualified class name. - * - * @param string $rootNamespace - * @param string $class - * - * @return string - */ - abstract protected function getNamespacedClass(string $rootNamespace, string $class): string; - - /** - * Builds the file path from the class name. - * - * @param string $class - * - * @return string - */ - protected function buildPath(string $class): string - { - $root = $this->getRootNamespace(); - $name = trim(str_replace($root, '', $class), '\\'); - - // Check if the namespace is actually defined and we are not just typing gibberish. - $base = Services::autoloader()->getNamespace($root); - - if (! $base = reset($base)) - { - throw new RuntimeException(lang('CLI.namespaceNotDefined', [$root])); - } - - $base = realpath($base) ?: $base; - $path = $base . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $name) . '.php'; - $filename = $this->modifyBasename(basename($path)); - - return implode(DIRECTORY_SEPARATOR, array_slice(explode(DIRECTORY_SEPARATOR, $path), 0, -1)) . DIRECTORY_SEPARATOR . $filename; - } - - /** - * Provides last chance for child generators to change - * the file's basename before saving. This is useful for - * migration files where the basename has a date component. - * - * @param string $filename - * - * @return string - */ - protected function modifyBasename(string $filename): string - { - return $filename; - } - - /** - * Builds the contents for class being generated, doing all - * the replacements necessary. - * - * @param string $class - * - * @return string - */ - protected function buildClassContents(string $class): string - { - return $this->setReplacements($this->getTemplate(), $class); - } - - /** - * Gets the template for this class. - * - * @return string - */ - abstract protected function getTemplate(): string; - - /** - * Retrieves the namespace part from the fully qualified class name. - * - * @param string $class - * - * @return string - */ - protected function getNamespace(string $class): string - { - return trim(implode('\\', array_slice(explode('\\', $class), 0, -1)), '\\'); - } - - /** - * Performs the necessary replacements. - * - * @param string $template - * @param string $class - * - * @return string - */ - protected function setReplacements(string $template, string $class): string - { - $namespaces = [ - 'DummyNamespace', - '{ namespace }', - '{namespace}', - ]; - - $classes = [ - 'DummyClass', - '{ class }', - '{class}', - ]; - - $template = str_replace($namespaces, $this->getNamespace($class), $template); - $class = str_replace($this->getNamespace($class) . '\\', '', $class); - - return str_replace($classes, $class, $template); - } - - /** - * Alphabetically sorts the imports for a given template. - * - * @param string $template - * - * @return string - */ - protected function sortImports(string $template): string - { - if ($this->sortImports && preg_match('/(?P(?:^use [^;]+;$\n?)+)/m', $template, $match)) - { - $imports = explode("\n", trim($match['imports'])); - sort($imports); - - return str_replace(trim($match['imports']), implode("\n", $imports), $template); - } - - return $template; - } - - /** - * Gets a generator view as defined in the `Config\Generators::$views`, - * with fallback to `$default` when the defined view does not exist. - * - * @param string $default Path to the fallback view. - * @param array $data Data to be passed to the view. - * - * @return string - */ - protected function getGeneratorViewFile(string $default, array $data = []): string - { - try - { - return view($this->config->views[$this->name], $data, ['debug' => false]); - } - catch (Throwable $e) - { - log_message('error', $e->getMessage()); - - return view($default, $data, ['debug' => false]); - } - } -} diff --git a/system/CLI/GeneratorTrait.php b/system/CLI/GeneratorTrait.php new file mode 100644 index 000000000000..10ed36497a9c --- /dev/null +++ b/system/CLI/GeneratorTrait.php @@ -0,0 +1,356 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CodeIgniter\CLI; + +use Config\Services; +use Throwable; + +/** + * GeneratorTrait contains a collection of methods + * to build the commands that generates a file. + */ +trait GeneratorTrait +{ + /** + * Component Name + * + * @var string + */ + protected $component; + + /** + * File directory + * + * @var string + */ + protected $directory; + + /** + * View template name + * + * @var string + */ + protected $template; + + /** + * Whether to require class name. + * + * @internal + * + * @var boolean + */ + private $hasClassName = true; + + /** + * Whether to sort class imports. + * + * @internal + * + * @var boolean + */ + private $sortImports = true; + + /** + * The params array for easy access by other methods. + * + * @internal + * + * @var array + */ + private $params = []; + + /** + * Execute the command. + * + * @param array $params + * + * @return void + */ + protected function execute(array $params): void + { + $this->params = $params; + + if ($this->getOption('namespace') === 'CodeIgniter') + { + CLI::write(lang('CLI.generator.usingCINamespace'), 'yellow'); + CLI::newLine(); + + // @codeCoverageIgnoreStart + if (CLI::prompt('Are you sure you want to continue?', ['y', 'n'], 'required') === 'n') + { + CLI::newLine(); + CLI::write(lang('CLI.cancelOperation'), 'light_yellow'); + CLI::newLine(); + + return; + } + // @codeCoverageIgnoreEnd + + CLI::newLine(); + } + + // 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; + } + + // 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') && file_exists($path)) + { + CLI::write(lang('CLI.generator.fileExist', [CLI::color(clean_path($path), 'red')])); + CLI::newLine(); + + return; + } + + // Check if the directory to save the file is existing. + $dir = dirname($path); + + if (! is_dir($dir)) + { + mkdir($dir, 0755, true); + } + + helper('filesystem'); + + // 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))) + { + CLI::write(lang('CLI.generator.fileError', [clean_path($path)]), 'red'); + CLI::newLine(); + + return; + } + + if ($this->getOption('force') && file_exists($path)) + { + CLI::write(lang('CLI.generator.fileOverwrite', [CLI::color(clean_path($path), 'yellow')])); + CLI::newLine(); + + return; + } + + CLI::write(lang('CLI.generator.fileCreate', [CLI::color(clean_path($path), 'light_green')])); + CLI::newLine(); + } + + /** + * Prepare options and do the necessary replacements. + * + * @param string $class + * + * @return string + */ + protected function prepare(string $class): string + { + return $this->parseTemplate($class); + } + + /** + * Change file basename before saving. + * + * Useful for components where the file name has a date. + * + * @param string $filename + * + * @return string + */ + protected function basename(string $filename): string + { + return basename($filename); + } + + /** + * Parses the class name and checks if it is already qualified. + * + * @return string + */ + protected function qualifyClassName(): string + { + // Gets the class name from input. + $class = $this->params[0] ?? CLI::getSegment(2); + + if (is_null($class) && $this->hasClassName) + { + // @codeCoverageIgnoreStart + $class = CLI::prompt(lang('CLI.generator.className'), null, 'required'); + CLI::newLine(); + // @codeCoverageIgnoreEnd + } + + helper('inflector'); + + $component = strtolower(singular($this->component)); + $class = strtolower($class); + $class = strpos($class, $component) !== false ? str_replace($component, ucfirst($component), $class) : $class; + + if ($this->getOption('suffix') && ! strripos($class, $component)) + { + $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))))), '\\/'); + + // Gets the root namespace from input. + $root = trim(str_replace('/', '\\', $this->getOption('namespace') ?? APP_NAMESPACE), '\\'); + + if (strncmp($class, $root, strlen($root)) === 0) + { + return $class; + } + + return $root . '\\' . $this->directory . '\\' . str_replace('/', '\\', $class); + } + + /** + * Gets the generator view as defined in the `Config\Generators::$views`, + * with fallback to `$template` when the defined view does not exist. + * + * @param array $data Data to be passed to the view. + * + * @return string + */ + protected function renderTemplate(array $data = []): string + { + try + { + return view(config('Generators')->views[$this->name], $data, ['debug' => false]); + } + catch (Throwable $e) + { + log_message('error', $e->getMessage()); + + return view("CodeIgniter\Commands\Generators\Views\\{$this->template}", $data, ['debug' => false]); + } + } + + /** + * Performs pseudo-variables contained within view file. + * + * @param string $class + * @param array $search + * @param array $replace + * @param array $data + * + * @return 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)), '\\'); + + array_push($search, '<@php', '{namespace}', '{class}'); + array_push($replace, 'renderTemplate($data)); + } + + /** + * Builds the contents for class being generated, doing all + * the replacements necessary, and alphabetically sorts the + * imports for a given template. + * + * @param string $class + * + * @return string + */ + protected function buildContent(string $class): string + { + $template = $this->prepare($class); + + if ($this->sortImports && preg_match('/(?P(?:^use [^;]+;$\n?)+)/m', $template, $match)) + { + $imports = explode("\n", trim($match['imports'])); + sort($imports); + + return str_replace(trim($match['imports']), implode("\n", $imports), $template); + } + + return $template; + } + + /** + * Builds the file path from the class name. + * + * @param string $class + * + * @return string + */ + protected function buildPath(string $class): string + { + $root = 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($root); + + if (! $base = reset($base)) + { + CLI::error(lang('CLI.namespaceNotDefined', [$root])); + CLI::newLine(); + + return ''; + } + + $base = realpath($base) ?: $base; + $file = $base . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, trim(str_replace($root, '', $class), '\\')) . '.php'; + + return implode(DIRECTORY_SEPARATOR, array_slice(explode(DIRECTORY_SEPARATOR, $file), 0, -1)) . DIRECTORY_SEPARATOR . $this->basename($file); + } + + /** + * Allows child generators to modify the internal `$hasClassName` flag. + * + * @param boolean $sort + */ + protected function setHasClassName(bool $hasClassName) + { + $this->hasClassName = $hasClassName; + } + + /** + * Allows child generators to modify the internal `$sortImports` flag. + * + * @param boolean $sort + */ + protected function setSortImports(bool $sortImports) + { + $this->sortImports = $sortImports; + } + + /** + * Gets a single command-line option. Returns TRUE if the option exists, + * but doesn't have a value, and is simply acting as a flag. + * + * @param string $name + * + * @return mixed + */ + protected function getOption(string $name) + { + if (! array_key_exists($name, $this->params)) + { + return CLI::getOption($name); + } + + return is_null($this->params[$name]) ? true : $this->params[$name]; + } +} diff --git a/system/Commands/Generators/CommandGenerator.php b/system/Commands/Generators/CommandGenerator.php new file mode 100644 index 000000000000..fc41c35ac3fe --- /dev/null +++ b/system/Commands/Generators/CommandGenerator.php @@ -0,0 +1,124 @@ + + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a skeleton command file. + */ +class CommandGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:command'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a new spark command.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:command [options]'; + + /** + * The Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'name' => 'The command class name.', + ]; + + /** + * The Command's Options + * + * @var array + */ + protected $options = [ + '--command' => 'The command name, Default: "command:name"', + '--type' => 'The command type. Options [basic, generator], Default: "basic".', + '--group' => 'The command group, Default: [basic -> "CodeIgniter", generator -> "Generators"].', + '--namespace' => 'Set root namespace, Default: "APP_NAMESPACE".', + '--suffix' => 'Append the component title to the class name (e.g. User => UserCommand).', + '--force' => 'Force overwrite existing file.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->component = 'Command'; + $this->directory = 'Commands'; + $this->template = 'command.tpl.php'; + + $this->execute($params); + } + + /** + * Prepare options and do the necessary replacements. + * + * @param string $class + * + * @return string + */ + protected function prepare(string $class): string + { + $command = $this->getOption('command'); + $group = $this->getOption('group'); + $type = $this->getOption('type'); + + $command = is_string($command) ? $command : 'command:name'; + $group = is_string($group) ? $group : 'CodeIgniter'; + $type = is_string($type) ? $type : 'basic'; + + if (! in_array($type, ['basic', 'generator'], true)) + { + // @codeCoverageIgnoreStart + $type = CLI::prompt(lang('CLI.generator.commandType'), ['basic', 'generator'], 'required'); + CLI::newLine(); + // @codeCoverageIgnoreEnd + } + + if ($type === 'generator') + { + $group = 'Generators'; + } + + return $this->parseTemplate( + $class, ['{group}', '{command}'], [$group, $command], ['type' => $type] + ); + } +} diff --git a/system/Commands/Generators/ConfigGenerator.php b/system/Commands/Generators/ConfigGenerator.php new file mode 100644 index 000000000000..fc6409cd2c78 --- /dev/null +++ b/system/Commands/Generators/ConfigGenerator.php @@ -0,0 +1,101 @@ + + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a skeleton Config file. + */ +class ConfigGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:config'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a new config file.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:config [options]'; + + /** + * The Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'name' => 'The config 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 => UserConfig).', + '--force' => 'Force overwrite existing file.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->component = 'Config'; + $this->directory = 'Config'; + $this->template = 'config.tpl.php'; + + $this->execute($params); + } + + /** + * Prepare options and do the necessary replacements. + * + * @param string $class + * + * @return string + */ + protected function prepare(string $class): string + { + $namespace = $this->getOption('namespace'); + $namespace = is_string($namespace) ? $namespace . '\\' . $this->directory : $this->directory; + + return $this->parseTemplate($class, ['{namespace}'], [$namespace]); + } +} diff --git a/system/Commands/Generators/ControllerGenerator.php b/system/Commands/Generators/ControllerGenerator.php new file mode 100644 index 000000000000..072c6e4dadad --- /dev/null +++ b/system/Commands/Generators/ControllerGenerator.php @@ -0,0 +1,141 @@ + + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a skeleton controller file. + */ +class ControllerGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:controller'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a new controller file.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:controller [options]'; + + /** + * The Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'name' => 'The controller class name.', + ]; + + /** + * The Command's Options + * + * @var array + */ + protected $options = [ + '--bare' => 'Extends from CodeIgniter\Controller instead of BaseController.', + '--restful' => 'Extends from a RESTful resource, Options: [controller, presenter], Default: "controller".', + '--namespace' => 'Set root namespace, Default: "APP_NAMESPACE".', + '--suffix' => 'Append the component title to the class name (e.g. User => UserController).', + '--force' => 'Force overwrite existing file.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->component = 'Controller'; + $this->directory = 'Controllers'; + $this->template = 'controller.tpl.php'; + + $this->execute($params); + } + + /** + * Prepare options and do the necessary replacements. + * + * @param string $class + * + * @return string + */ + protected function prepare(string $class): string + { + $bare = $this->getOption('bare'); + $rest = $this->getOption('restful'); + + $useStatement = trim(APP_NAMESPACE, '\\') . '\Controllers\BaseController'; + $extends = 'BaseController'; + + // Gets the appropriate parent class to extend. + if ($bare || $rest) + { + if ($bare) + { + $useStatement = 'CodeIgniter\Controller'; + $extends = 'Controller'; + } + elseif ($rest) + { + $rest = is_string($rest) ? $rest : 'controller'; + + if (! in_array($rest, ['controller', 'presenter'], true)) + { + // @codeCoverageIgnoreStart + $rest = CLI::prompt(lang('CLI.generator.parentClass'), ['controller', 'presenter'], 'required'); + CLI::newLine(); + // @codeCoverageIgnoreEnd + } + + if ($rest === 'controller') + { + $useStatement = 'CodeIgniter\RESTful\ResourceController'; + $extends = 'ResourceController'; + } + elseif ($rest === 'presenter') + { + $useStatement = 'CodeIgniter\RESTful\ResourcePresenter'; + $extends = 'ResourcePresenter'; + } + } + } + + return $this->parseTemplate( + $class, ['{useStatement}', '{extends}'], [$useStatement, $extends], ['type' => $rest] + ); + } +} diff --git a/system/Commands/Generators/CreateCommand.php b/system/Commands/Generators/CreateCommand.php deleted file mode 100644 index 641cf638db5f..000000000000 --- a/system/Commands/Generators/CreateCommand.php +++ /dev/null @@ -1,243 +0,0 @@ - - * - * 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\CLI; -use CodeIgniter\CLI\GeneratorCommand; - -class CreateCommand extends GeneratorCommand -{ - /** - * The Command's name - * - * @var string - */ - protected $name = 'make:command'; - - /** - * The Command's short description - * - * @var string - */ - protected $description = 'Creates a new spark command.'; - - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'make:command [options]'; - - /** - * The Command's arguments - * - * @var array - */ - protected $arguments = [ - 'name' => 'The command class name', - ]; - - /** - * The Command's options - * - * @var array - */ - protected $options = [ - '--command' => 'The command name. Defaults to "command:name"', - '--group' => 'The group of command. Defaults to "CodeIgniter" for basic commands, and "Generators" for generator commands.', - '--type' => 'Type of command. Whether a basic command or a generator command. Defaults to "basic".', - ]; - - /** - * {@inheritDoc} - */ - protected function getClassName(): string - { - $className = parent::getClassName(); - - if (empty($className)) - { - $className = CLI::prompt(lang('CLI.generateClassName'), null, 'required'); // @codeCoverageIgnore - } - - return $className; - } - - /** - * {@inheritDoc} - */ - protected function getNamespacedClass(string $rootNamespace, string $class): string - { - return $rootNamespace . '\\Commands\\' . $class; - } - - /** - * {@inheritDoc} - */ - protected function getTemplate(): string - { - $template = $this->getGeneratorViewFile('CodeIgniter\\Commands\\Generators\\Views\\command.tpl.php'); - - return str_replace('<@php', 'params['command'] ?? CLI::getOption('command'); - $commandGroup = $this->params['group'] ?? CLI::getOption('group'); - $commandType = $this->params['type'] ?? CLI::getOption('type'); - - // Resolve options - if (! is_string($commandName)) - { - $commandName = 'command:name'; - } - - if (! is_string($commandType)) - { - $commandType = 'basic'; - } - // @codeCoverageIgnoreStart - elseif (! in_array($commandType, ['basic', 'generator'], true)) - { - $commandType = CLI::prompt('Command type', ['basic', 'generator'], 'required'); - } - // @codeCoverageIgnoreEnd - - if ($commandType === 'generator') - { - $useStatement = 'use CodeIgniter\\CLI\\GeneratorCommand;'; - $extends = 'extends GeneratorCommand'; - } - else - { - $useStatement = 'use CodeIgniter\\CLI\\BaseCommand;'; - $extends = 'extends BaseCommand'; - } - - if (! is_string($commandGroup)) - { - $commandGroup = $commandType === 'generator' ? 'Generators' : 'CodeIgniter'; - } - $commandGroup = $this->getCommandGroupProperty($commandType, $commandGroup); - - $commandAbstractMethodsToImplement = $this->getRequiredAbstractMethodsToImplement($commandType); - - // Do the replacements - $template = parent::setReplacements($template, $class); - - return str_replace([ - '{useStatement}', - '{extends}', - '{commandGroup}', - '{commandName}', - '{commandAbstractMethodsToImplement}', - ], [ - $useStatement, - $extends, - $commandGroup, - $commandName, - $commandAbstractMethodsToImplement, - ], - $template - ); - } - - /** - * Gets the proper class property for group name. - * - * @param string $type - * - * @return string - */ - protected function getCommandGroupProperty(string $type, string $group): string - { - if ($type === 'generator' && $group === 'Generators') - { - // Assume it is already extending from Generator Command - // so this is really redundant. - return ''; - } - - return << - * - * 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\CLI; -use CodeIgniter\CLI\GeneratorCommand; - -/** - * Creates a skeleton controller file. - */ -class CreateController extends GeneratorCommand -{ - /** - * The Command's name - * - * @var string - */ - protected $name = 'make:controller'; - - /** - * The Command's short description - * - * @var string - */ - protected $description = 'Creates a new controller file.'; - - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'make:controller [options]'; - - /** - * The Command's arguments - * - * @var array - */ - protected $arguments = [ - 'name' => 'The controller class name', - ]; - - /** - * The Command's options - * - * @var array - */ - protected $options = [ - '--bare' => 'Extends from CodeIgniter\\Controller instead of BaseController', - '--restful' => 'Extends from a RESTful resource. Options are \'controller\' or \'presenter\'.', - ]; - - /** - * {@inheritDoc} - */ - protected function getClassName(): string - { - $className = parent::getClassName(); - - if (empty($className)) - { - $className = CLI::prompt(lang('CLI.generateClassName'), null, 'required'); // @codeCoverageIgnore - } - - return $className; - } - - /** - * {@inheritDoc} - */ - protected function getNamespacedClass(string $rootNamespace, string $class): string - { - return $rootNamespace . '\\Controllers\\' . $class; - } - - /** - * {@inheritDoc} - */ - protected function getTemplate(): string - { - $template = $this->getGeneratorViewFile('CodeIgniter\\Commands\\Generators\\Views\\controller.tpl.php'); - - return str_replace('<@php', 'params) || CLI::getOption('bare'); - $rest = array_key_exists('restful', $this->params) - ? $this->params['restful'] ?? true - : CLI::getOption('restful'); - - [ - $useStatement, - $extends, - $restfulMethods, - ] = $this->getParentClass($bare, $rest); - - $template = parent::setReplacements($template, $class); - - return str_replace([ - '{useStatement}', - '{extends}', - '{restfulMethods}', - ], [ - $useStatement, - $extends, - $restfulMethods, - ], - $template - ); - } - - /** - * Gets the appropriate parent class to extend. - * - * @param boolean|null $bare - * @param string|boolean|null $rest - * - * @return array - */ - protected function getParentClass(?bool $bare, $rest): array - { - $restfulMethods = ''; - - if (! $bare && ! $rest) - { - $appNamespace = trim(APP_NAMESPACE, '\\'); - $useStatement = "use {$appNamespace}\\Controllers\\BaseController;"; - $extends = 'extends BaseController'; - } - elseif ($bare) - { - $useStatement = 'use CodeIgniter\\Controller;'; - $extends = 'extends Controller'; - } - else - { - if ($rest === true) - { - $type = 'controller'; - } - elseif (in_array($rest, ['controller', 'presenter'], true)) - { - $type = $rest; - } - else - { - $type = CLI::prompt(lang('CLI.generateParentClass'), ['controller', 'presenter'], 'required'); // @codeCoverageIgnore - } - - $restfulMethods = $this->getAdditionalRestfulMethods(); - - $type = ucfirst($type); - $useStatement = "use CodeIgniter\\RESTful\\Resource{$type};"; - $extends = "extends Resource{$type}"; - } - - return [ - $useStatement, - $extends, - $restfulMethods, - ]; - } - - /** - * If the controller extends any RESTful controller, this will provide - * the additional REST API methods. - * - * @return string - */ - protected function getAdditionalRestfulMethods(): string - { - return <<<'EOF' - - /** - * Return the properties of a resource object - * - * @return array - */ - public function show($id = null) - { - // - } - - /** - * Return a new resource object, with default properties - * - * @return array - */ - public function new() - { - // - } - - /** - * Create a new resource object, from "posted" parameters - * - * @return array - */ - public function create() - { - // - } - - /** - * Return the editable properties of a resource object - * - * @return array - */ - public function edit($id = null) - { - // - } - - /** - * Add or update a model resource, from "posted" properties - * - * @return array - */ - public function update($id = null) - { - // - } - - /** - * Delete the designated resource object from the model - * - * @return array - */ - public function delete($id = null) - { - // - } - -EOF; - } -} diff --git a/system/Commands/Generators/CreateEntity.php b/system/Commands/Generators/CreateEntity.php deleted file mode 100644 index fcea6992baa5..000000000000 --- a/system/Commands/Generators/CreateEntity.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * 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\CLI; -use CodeIgniter\CLI\GeneratorCommand; - -/** - * Creates a skeleton Entity file. - */ -class CreateEntity extends GeneratorCommand -{ - /** - * The Command's name - * - * @var string - */ - protected $name = 'make:entity'; - - /** - * The Command's short description - * - * @var string - */ - protected $description = 'Creates a new entity file.'; - - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'make:entity [options]'; - - /** - * The Command's arguments - * - * @var array - */ - protected $arguments = [ - 'name' => 'The model class name', - ]; - - /** - * {@inheritDoc} - */ - protected function getClassName(): string - { - $className = parent::getClassName(); - - if (empty($className)) - { - $className = CLI::prompt(lang('CLI.generateClassName'), null, 'required'); // @codeCoverageIgnore - } - - return $className; - } - - /** - * {@inheritDoc} - */ - protected function getNamespacedClass(string $rootNamespace, string $class): string - { - return $rootNamespace . '\\Entities\\' . $class; - } - - /** - * {@inheritDoc} - */ - protected function getTemplate(): string - { - $template = $this->getGeneratorViewFile('CodeIgniter\\Commands\\Generators\\Views\\entity.tpl.php'); - - return str_replace('<@php', ' - * - * 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\CLI; -use CodeIgniter\CLI\GeneratorCommand; - -/** - * Creates a skeleton Filter file. - */ -class CreateFilter extends GeneratorCommand -{ - /** - * The Command's name - * - * @var string - */ - protected $name = 'make:filter'; - - /** - * The Command's short description - * - * @var string - */ - protected $description = 'Creates a new filter file.'; - - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'make:filter [options]'; - - /** - * The Command's arguments - * - * @var array - */ - protected $arguments = [ - 'name' => 'The filter class name', - ]; - - /** - * {@inheritDoc} - */ - protected function getClassName(): string - { - $className = parent::getClassName(); - - if (empty($className)) - { - $className = CLI::prompt(lang('CLI.generateClassName'), null, 'required'); // @codeCoverageIgnore - } - - return $className; - } - - /** - * {@inheritDoc} - */ - protected function getNamespacedClass(string $rootNamespace, string $class): string - { - return $rootNamespace . '\\Filters\\' . $class; - } - - /** - * {@inheritDoc} - */ - protected function getTemplate(): string - { - $template = $this->getGeneratorViewFile('CodeIgniter\\Commands\\Generators\\Views\\filter.tpl.php'); - - return str_replace('<@php', ' - * - * 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\CLI; -use CodeIgniter\CLI\GeneratorCommand; - -/** - * Creates a new migration file. - */ -class CreateMigration extends GeneratorCommand -{ - /** - * The Command's name - * - * @var string - */ - protected $name = 'make:migration'; - - /** - * The Command's short description - * - * @var string - */ - protected $description = 'Creates a new migration file.'; - - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'make:migration [options]'; - - /** - * The Command's Arguments - * - * @var array - */ - protected $arguments = [ - 'name' => 'The migration file name', - ]; - - /** - * {@inheritDoc} - */ - protected function getClassName(): string - { - $class = parent::getClassName(); - - if (empty($class)) - { - $class = CLI::prompt(lang('Migrations.nameMigration'), null, 'required'); // @codeCoverageIgnore - } - - return $class; - } - - /** - * {@inheritDoc} - */ - protected function getNamespacedClass(string $rootNamespace, string $class): string - { - return $rootNamespace . '\\Database\\Migrations\\' . $class; - } - - /** - * {@inheritDoc} - */ - protected function modifyBasename(string $filename): string - { - return gmdate(config('Migrations')->timestampFormat) . $filename; - } - - /** - * {@inheritDoc} - */ - protected function getTemplate(): string - { - $template = $this->getGeneratorViewFile('CodeIgniter\\Commands\\Generators\\Views\\migration.tpl.php'); - - return str_replace('<@php', ' - * - * 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\CLI; -use CodeIgniter\CLI\GeneratorCommand; - -/** - * Creates a skeleton Model file. - */ -class CreateModel extends GeneratorCommand -{ - /** - * The Command's name - * - * @var string - */ - protected $name = 'make:model'; - - /** - * The Command's short description - * - * @var string - */ - protected $description = 'Creates a new model file.'; - - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'make:model [options]'; - - /** - * The Command's arguments - * - * @var array - */ - protected $arguments = [ - 'name' => 'The model class name', - ]; - - /** - * The Command's options - * - * @var array - */ - protected $options = [ - '--dbgroup' => 'Database group to use. Defaults to "default".', - '--entity' => 'Use an Entity as return type.', - '--table' => 'Supply a different table name. Defaults to the pluralized name.', - ]; - - /** - * {@inheritDoc} - */ - protected function getClassName(): string - { - $className = parent::getClassName(); - - if (empty($className)) - { - $className = CLI::prompt(lang('CLI.generateClassName'), null, 'required'); // @codeCoverageIgnore - } - - return $className; - } - - /** - * {@inheritDoc} - */ - protected function getNamespacedClass(string $rootNamespace, string $class): string - { - return $rootNamespace . '\\Models\\' . $class; - } - - /** - * {@inheritDoc} - */ - protected function getTemplate(): string - { - $dbgroup = $this->params['dbgroup'] ?? CLI::getOption('dbgroup'); - - if (! is_string($dbgroup)) - { - $dbgroup = 'default'; - } - - $template = $this->getGeneratorViewFile('CodeIgniter\\Commands\\Generators\\Views\\model.tpl.php'); - - return str_replace(['<@php', '{dbgroup}'], ['params) || CLI::getOption('entity'); - - if (! $entity) - { - $entity = 'array'; // default to array return - } - else - { - $entity = str_replace('\\Models', '\\Entities', $class); - - if ($pos = strripos($entity, 'Model')) - { - // Strip 'Model' from name - $entity = substr($entity, 0, $pos); - } - } - - $template = str_replace('{return}', $entity, $template); - $table = $this->params['table'] ?? CLI::getOption('table'); - - if (! is_string($table)) - { - $table = str_replace($this->getNamespace($class) . '\\', '', $class); - } - - if ($pos = strripos($table, 'Model')) - { - $table = substr($table, 0, $pos); - } - - // transform class name to lowercased plural for table name - $table = strtolower(plural($table)); - - return str_replace('{table}', $table, $template); - } -} diff --git a/system/Commands/Generators/CreateScaffold.php b/system/Commands/Generators/CreateScaffold.php deleted file mode 100644 index b0f4db605a24..000000000000 --- a/system/Commands/Generators/CreateScaffold.php +++ /dev/null @@ -1,117 +0,0 @@ - - * - * 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\CLI; - -class CreateScaffold extends BaseCommand -{ - /** - * The group the command is lumped under - * when listing commands. - * - * @var string - */ - protected $group = 'Generators'; - - /** - * The Command's name - * - * @var string - */ - protected $name = 'make:scaffold'; - - /** - * The Command's short description - * - * @var string - */ - protected $description = 'Creates a complete set of scaffold files.'; - - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'make:scaffold [options]'; - - /** - * The Command's arguments - * - * @var array - */ - protected $arguments = [ - 'name' => 'The class name', - ]; - - /** - * The Command's options. - * - * @var array - */ - protected $options = [ - '--bare' => 'Add the \'-bare\' option to controller scaffold.', - '--restful' => 'Add the \'-restful\' option to controller scaffold.', - '--dbgroup' => 'Add the \'-dbgroup\' option to model scaffold.', - '--table' => 'Add the \'-table\' option to the model scaffold.', - '-n' => 'Set root namespace. Defaults to APP_NAMESPACE.', - '--force' => 'Force overwrite existing files.', - ]; - - /** - * {@inheritDoc} - */ - public function run(array $params) - { - // Resolve options - $bare = array_key_exists('bare', $params) || CLI::getOption('bare'); - $rest = array_key_exists('restful', $params) ? ($params['restful'] ?? true) : CLI::getOption('restful'); - $group = array_key_exists('dbgroup', $params) ? ($params['dbgroup'] ?? 'default') : CLI::getOption('dbgroup'); - $tableModel = $params['table'] ?? CLI::getOption('table'); - $namespace = $params['n'] ?? CLI::getOption('n'); - $force = array_key_exists('force', $params) || CLI::getOption('force'); - - // Sets additional options - $genOptions = ['n' => $namespace]; - - if ($force) - { - $genOptions['force'] = null; - } - - $controllerOpts = []; - - if ($bare) - { - $controllerOpts['bare'] = null; - } - elseif ($rest) - { - $controllerOpts['restful'] = $rest; - } - - $modelOpts = [ - 'dbgroup' => $group, - 'entity' => null, - 'table' => $tableModel, - ]; - - // Call those commands! - $class = $params[0] ?? CLI::getSegment(2); - $this->call('make:controller', array_merge([$class], $controllerOpts, $genOptions)); - $this->call('make:model', array_merge([$class], $modelOpts, $genOptions)); - $this->call('make:entity', array_merge([$class], $genOptions)); - $this->call('make:migration', array_merge([$class], $genOptions)); - $this->call('make:seeder', array_merge([$class], $genOptions)); - } -} diff --git a/system/Commands/Generators/CreateSeeder.php b/system/Commands/Generators/CreateSeeder.php deleted file mode 100644 index f56e5bbec665..000000000000 --- a/system/Commands/Generators/CreateSeeder.php +++ /dev/null @@ -1,93 +0,0 @@ - - * - * 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\CLI; -use CodeIgniter\CLI\GeneratorCommand; - -/** - * Creates a new seeder file - */ -class CreateSeeder extends GeneratorCommand -{ - /** - * The Command's name - * - * @var string - */ - protected $name = 'make:seeder'; - - /** - * the Command's short description - * - * @var string - */ - protected $description = 'Creates a new seeder file.'; - - /** - * the Command's usage - * - * @var string - */ - protected $usage = 'make:seeder [options]'; - - /** - * the Command's Arguments - * - * @var array - */ - protected $arguments = [ - 'name' => 'The seeder file name', - ]; - - /** - * Gets the class name from input. - * - * @return string - */ - protected function getClassName(): string - { - $class = parent::getClassName(); - - if (empty($class)) - { - $class = CLI::prompt(lang('Migrations.nameSeeder'), null, 'required'); // @codeCoverageIgnore - } - - return $class; - } - - /** - * Gets the qualified class name. - * - * @param string $rootNamespace - * @param string $class - * - * @return string - */ - protected function getNamespacedClass(string $rootNamespace, string $class): string - { - return $rootNamespace . '\\Database\\Seeds\\' . $class; - } - - /** - * Gets the template for this class. - * - * @return string - */ - protected function getTemplate(): string - { - $template = $this->getGeneratorViewFile('CodeIgniter\\Commands\\Generators\\Views\\seed.tpl.php'); - - return str_replace('<@php', ' - * - * 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\CLI; -use CodeIgniter\CLI\GeneratorCommand; - -/** - * Creates a migration file for database sessions. - */ -class CreateSessionMigration extends GeneratorCommand -{ - /** - * The Command's name - * - * @var string - */ - protected $name = 'session:migration'; - - /** - * the Command's short description - * - * @var string - */ - protected $description = 'Generates the migration file for database sessions.'; - - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'session:migration [options]'; - - /** - * The Command's Options - * - * @var array - */ - protected $options = [ - '-g' => 'Set database group', - '-t' => 'Set table name', - ]; - - /** - * {@inheritDoc} - */ - protected function getClassName(): string - { - $tableName = $this->params['t'] ?? CLI::getOption('t') ?? 'ci_sessions'; - - return "Migration_create_{$tableName}_table"; - } - - /** - * {@inheritDoc} - */ - protected function getNamespacedClass(string $rootNamespace, string $class): string - { - return $rootNamespace . '\\Database\\Migrations\\' . $class; - } - - /** - * {@inheritDoc} - */ - protected function modifyBasename(string $filename): string - { - return str_replace('Migration', gmdate(config('Migrations')->timestampFormat), $filename); - } - - /** - * {@inheritDoc} - */ - protected function getTemplate(): string - { - $data = [ - 'DBGroup' => $this->params['g'] ?? CLI::getOption('g'), - 'tableName' => $this->params['t'] ?? CLI::getOption('t') ?? 'ci_sessions', - 'matchIP' => config('App')->sessionMatchIP ?? false, - ]; - - $template = $this->getGeneratorViewFile('CodeIgniter\\Commands\\Generators\\Views\\session_migration.tpl.php', $data); - - return str_replace('<@php', ' + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a skeleton Entity file. + */ +class EntityGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:entity'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a new entity file.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:entity [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 => UserEntity).', + '--force' => 'Force overwrite existing file.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->component = 'Entity'; + $this->directory = 'Entities'; + $this->template = 'entity.tpl.php'; + + $this->execute($params); + } +} diff --git a/system/Commands/Generators/FilterGenerator.php b/system/Commands/Generators/FilterGenerator.php new file mode 100644 index 000000000000..080239dea673 --- /dev/null +++ b/system/Commands/Generators/FilterGenerator.php @@ -0,0 +1,86 @@ + + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a skeleton Filter file. + */ +class FilterGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:filter'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a new filter file.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:filter [options]'; + + /** + * The Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'name' => 'The filter 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 => UserFilter).', + '--force' => 'Force overwrite existing file.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->component = 'Filter'; + $this->directory = 'Filters'; + $this->template = 'filter.tpl.php'; + + $this->execute($params); + } +} diff --git a/system/Commands/Generators/MigrationGenerator.php b/system/Commands/Generators/MigrationGenerator.php new file mode 100644 index 000000000000..c23e32bba90c --- /dev/null +++ b/system/Commands/Generators/MigrationGenerator.php @@ -0,0 +1,131 @@ + + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a skeleton migration file. + */ +class MigrationGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:migration'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a new migration file.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:migration [options]'; + + /** + * The Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'name' => 'The migration class name.', + ]; + + /** + * The Command's Options + * + * @var array + */ + protected $options = [ + '--session' => 'Generates the migration file for database sessions.', + '--table' => 'Supply a table name.', + '--dbgroup' => 'Database group to use, Default: "default".', + '--namespace' => 'Set root namespace, Default: "APP_NAMESPACE".', + '--suffix' => 'Append the component title to the class name (e.g. User => UserMigration).', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->component = 'Migration'; + $this->directory = 'Database\Migrations'; + $this->template = 'migration.tpl.php'; + + if (array_key_exists('session', $params) || CLI::getOption('session')) + { + $table = $params['table'] ?? CLI::getOption('table') ?? 'ci_sessions'; + $params[0] = "_create_{$table}_table"; + } + + $this->execute($params); + } + + /** + * Prepare options and do the necessary replacements. + * + * @param string $class + * + * @return string + */ + protected function prepare(string $class): string + { + $data['session'] = false; + + if ($this->getOption('session')) + { + $table = $this->getOption('table'); + $DBGroup = $this->getOption('dbgroup'); + + $data['session'] = true; + $data['table'] = is_string($table) ? $table : 'ci_sessions'; + $data['DBGroup'] = is_string($DBGroup) ? $DBGroup : 'default'; + $data['matchIP'] = config('App')->sessionMatchIP; + } + + return $this->parseTemplate($class, [], [], $data); + } + + /** + * Change file basename before saving. + * + * @param string $filename + * + * @return string + */ + protected function basename(string $filename): string + { + return gmdate(config('Migrations')->timestampFormat) . basename($filename); + } +} diff --git a/system/Commands/Generators/ModelGenerator.php b/system/Commands/Generators/ModelGenerator.php new file mode 100644 index 000000000000..abaaebcd41f0 --- /dev/null +++ b/system/Commands/Generators/ModelGenerator.php @@ -0,0 +1,139 @@ + + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a skeleton Model file. + */ +class ModelGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:model'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a new model file.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:model [options]'; + + /** + * The Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'name' => 'The model class name.', + ]; + + /** + * The Command's Options + * + * @var array + */ + protected $options = [ + '--table' => 'Supply a table name.', + '--dbgroup' => 'Database group to use, Default: "default".', + '--return' => 'Return type, Options: [array, object, entity], Default: "array".', + '--namespace' => 'Set root namespace, Default: "APP_NAMESPACE".', + '--suffix' => 'Append the component title to the class name (e.g. User => UserModel).', + '--force' => 'Force overwrite existing file.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->component = 'Model'; + $this->directory = 'Models'; + $this->template = 'model.tpl.php'; + + $this->execute($params); + } + + /** + * Prepare options and do the necessary replacements. + * + * @param string $class + * + * @return string + */ + protected function prepare(string $class): string + { + $table = $this->getOption('table'); + $DBGroup = $this->getOption('dbgroup'); + $return = $this->getOption('return'); + + $baseClass = strtolower(str_replace(trim(implode('\\', array_slice(explode('\\', $class), 0, -1)), '\\') . '\\', '', $class)); + $baseClass = strpos($baseClass, 'model') ? str_replace('model', '', $baseClass) : $baseClass; + + $table = is_string($table) ? $table : plural($baseClass); + $DBGroup = is_string($DBGroup) ? $DBGroup : 'default'; + $return = is_string($return) ? $return : 'array'; + + if (! in_array($return, ['array', 'object', 'entity'], true)) + { + // @codeCoverageIgnoreStart + $return = CLI::prompt(lang('CLI.generator.returnType'), ['array', 'object', 'entity'], 'required'); + CLI::newLine(); + // @codeCoverageIgnoreEnd + } + + if ($return === 'entity') + { + $return = str_replace('Models', 'Entities', $class); + + if ($pos = strpos($return, 'Model')) + { + $return = substr($return, 0, $pos); + + if ($this->getOption('suffix')) + { + $return .= 'Entity'; + } + } + + $this->call('make:entity', array_merge([$baseClass], $this->params)); + } + + return $this->parseTemplate( + $class, ['{table}', '{DBGroup}', '{return}'], [$table, $DBGroup, $return] + ); + } +} diff --git a/system/Commands/Generators/ScaffoldGenerator.php b/system/Commands/Generators/ScaffoldGenerator.php new file mode 100644 index 000000000000..378171dea5e8 --- /dev/null +++ b/system/Commands/Generators/ScaffoldGenerator.php @@ -0,0 +1,129 @@ + + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a complete set of scaffold files. + */ +class ScaffoldGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:scaffold'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a complete set of scaffold files.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:scaffold [options]'; + + /** + * The Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'name' => 'The class name', + ]; + + /** + * The Command's Options + * + * @var array + */ + protected $options = [ + '--bare' => 'Add the \'-bare\' option to controller scaffold.', + '--restful' => 'Add the \'-restful\' option to controller scaffold.', + '--table' => 'Add the \'-table\' option to the model scaffold.', + '--dbgroup' => 'Add the \'-dbgroup\' option to model scaffold.', + '--return' => 'Add the \'-return\' option to the model scaffold.', + '--namespace' => 'Set root namespace, Default: "APP_NAMESPACE".', + '--suffix' => 'Append the component title to the class name (e.g. User => UserComponent).', + '--force' => 'Force overwrite existing file.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->params = $params; + + $options = []; + + if ($this->getOption('namespace')) + { + $options['namespace'] = $this->getOption('namespace'); + } + + if ($this->getOption('suffix')) + { + $options['suffix'] = null; + } + + if ($this->getOption('force')) + { + $options['force'] = null; + } + + $controllerOpts = []; + + if ($this->getOption('bare')) + { + $controllerOpts['bare'] = null; + } + elseif ($this->getOption('restful')) + { + $controllerOpts['restful'] = $this->getOption('restful'); + } + + $modelOpts = [ + 'table' => $this->getOption('table'), + 'dbgroup' => $this->getOption('dbgroup'), + 'return' => $this->getOption('return'), + ]; + + $class = $params[0] ?? CLI::getSegment(2); + + // Call those commands! + $this->call('make:controller', array_merge([$class], $controllerOpts, $options)); + $this->call('make:model', array_merge([$class], $modelOpts, $options)); + $this->call('make:migration', array_merge([$class], $options)); + $this->call('make:seeder', array_merge([$class], $options)); + } +} diff --git a/system/Commands/Generators/SeederGenerator.php b/system/Commands/Generators/SeederGenerator.php new file mode 100644 index 000000000000..586f65684217 --- /dev/null +++ b/system/Commands/Generators/SeederGenerator.php @@ -0,0 +1,86 @@ + + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a skeleton seeder file. + */ +class SeederGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'make:seeder'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = 'Generates a new seeder file.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'make:seeder [options]'; + + /** + * The Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'name' => 'The seeder 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 => UserSeeder).', + '--force' => 'Force overwrite existing file.', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->component = 'Seeder'; + $this->directory = 'Database\Seeds'; + $this->template = 'seeder.tpl.php'; + + $this->execute($params); + } +} diff --git a/system/Commands/Generators/SessionMigrationGenerator.php b/system/Commands/Generators/SessionMigrationGenerator.php new file mode 100644 index 000000000000..4afb0cd848b0 --- /dev/null +++ b/system/Commands/Generators/SessionMigrationGenerator.php @@ -0,0 +1,121 @@ + + * + * 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\CLI; +use CodeIgniter\CLI\GeneratorTrait; + +/** + * Generates a migration file for database sessions. + * + * @deprecated Use make:migration instead. + * + * @codeCoverageIgnore + */ +class SessionMigrationGenerator extends BaseCommand +{ + use GeneratorTrait; + + /** + * The Command's Group + * + * @var string + */ + protected $group = 'Generators'; + + /** + * The Command's Name + * + * @var string + */ + protected $name = 'session:migration'; + + /** + * The Command's Description + * + * @var string + */ + protected $description = '[DEPRECATED] Generates the migration file for database sessions, Please use "make:migration --session" instead.'; + + /** + * The Command's Usage + * + * @var string + */ + protected $usage = 'session:migration [options]'; + + /** + * The Command's Options + * + * @var array + */ + protected $options = [ + '-t' => 'Supply a table name.', + '-g' => 'Database group to use, Default: "default".', + ]; + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + $this->component = 'Migration'; + $this->directory = 'Database\Migrations'; + $this->template = 'migration.tpl.php'; + + $table = 'ci_sessions'; + + if (array_key_exists('t', $params) || CLI::getOption('t')) + { + $table = $params['t'] ?? CLI::getOption('t'); + } + + $params[0] = "_create_{$table}_table"; + + $this->execute($params); + } + + /** + * Performs the necessary replacements. + * + * @param string $class + * + * @return string + */ + protected function prepare(string $class): string + { + $data['session'] = true; + $data['table'] = $this->getOption('t'); + $data['DBGroup'] = $this->getOption('g'); + $data['matchIP'] = config('App')->sessionMatchIP ?? false; + + $data['table'] = is_string($data['table']) ? $data['table'] : 'ci_sessions'; + $data['DBGroup'] = is_string($data['DBGroup']) ? $data['DBGroup'] : 'default'; + + return $this->parseTemplate($class, [], [], $data); + } + + /** + * Change file basename before saving. + * + * @param string $filename + * + * @return string + */ + protected function basename(string $filename): string + { + return gmdate(config('Migrations')->timestampFormat) . basename($filename); + } +} diff --git a/system/Commands/Generators/Views/command.tpl.php b/system/Commands/Generators/Views/command.tpl.php index 08183d5d6fda..52da0d0ba012 100644 --- a/system/Commands/Generators/Views/command.tpl.php +++ b/system/Commands/Generators/Views/command.tpl.php @@ -2,45 +2,75 @@ namespace {namespace}; +use CodeIgniter\CLI\BaseCommand; use CodeIgniter\CLI\CLI; -{useStatement} + +use CodeIgniter\CLI\GeneratorTrait; + -class {class} {extends} +class {class} extends BaseCommand { - {commandGroup} + + use GeneratorTrait; + + + /** + * The Command's Group + * + * @var string + */ + protected $group = '{group}'; + /** - * The Command's name + * The Command's Name * * @var string */ - protected $name = '{commandName}'; + protected $name = '{command}'; /** - * The Command's short description + * The Command's Description * * @var string */ protected $description = ''; /** - * The Command's usage + * The Command's Usage * * @var string */ - protected $usage = '{commandName} [arguments] [options]'; + protected $usage = '{command} [arguments] [options]'; /** - * The Command's arguments. + * The Command's Arguments * * @var array */ protected $arguments = []; /** - * The Command's options. + * The Command's Options * * @var array */ protected $options = []; - {commandAbstractMethodsToImplement} + + /** + * Actually execute a command. + * + * @param array $params + */ + public function run(array $params) + { + + $this->component = 'Command'; + $this->directory = 'Commands'; + $this->template = 'command.tpl.php'; + + $this->execute($params); + + // + + } } diff --git a/system/Commands/Generators/Views/config.tpl.php b/system/Commands/Generators/Views/config.tpl.php new file mode 100644 index 000000000000..72e93ad01aa8 --- /dev/null +++ b/system/Commands/Generators/Views/config.tpl.php @@ -0,0 +1,10 @@ +<@php + +namespace {namespace}; + +use CodeIgniter\Config\BaseConfig; + +class {class} extends BaseConfig +{ + // +} diff --git a/system/Commands/Generators/Views/controller.tpl.php b/system/Commands/Generators/Views/controller.tpl.php index 7257883b7bda..d389d3d5b34d 100644 --- a/system/Commands/Generators/Views/controller.tpl.php +++ b/system/Commands/Generators/Views/controller.tpl.php @@ -2,13 +2,176 @@ namespace {namespace}; -{useStatement} +use {useStatement}; -class {class} {extends} +class {class} extends {extends} { + + /** + * Return an array of resource objects, themselves in array format + * + * @return mixed + */ public function index() { // } - {restfulMethods} + + /** + * Return the properties of a resource object + * + * @return mixed + */ + public function show($id = null) + { + // + } + + /** + * Return a new resource object, with default properties + * + * @return mixed + */ + public function new() + { + // + } + + /** + * Create a new resource object, from "posted" parameters + * + * @return mixed + */ + public function create() + { + // + } + + /** + * Return the editable properties of a resource object + * + * @return mixed + */ + public function edit($id = null) + { + // + } + + /** + * Add or update a model resource, from "posted" properties + * + * @return mixed + */ + public function update($id = null) + { + // + } + + /** + * Delete the designated resource object from the model + * + * @return mixed + */ + public function delete($id = null) + { + // + } + + /** + * Present a view of resource objects + * + * @return mixed + */ + public function index() + { + // + } + + /** + * Present a view to present a specific resource object + * + * @param mixed $id + * + * @return mixed + */ + public function show($id = null) + { + // + } + + /** + * Present a view to present a new single resource object + * + * @return mixed + */ + public function new() + { + // + } + + /** + * Process the creation/insertion of a new resource object. + * This should be a POST. + * + * @return mixed + */ + public function create() + { + // + } + + /** + * Present a view to edit the properties of a specific resource object + * + * @param mixed $id + * + * @return mixed + */ + public function edit($id = null) + { + // + } + + /** + * Process the updating, full or partial, of a specific resource object. + * This should be a POST. + * + * @param mixed $id + * + * @return mixed + */ + public function update($id = null) + { + // + } + + /** + * Present a view to confirm the deletion of a specific resource object + * + * @param mixed $id + * + * @return mixed + */ + public function remove($id = null) + { + // + } + + /** + * Process the deletion of a specific resource object + * + * @param mixed $id + * + * @return mixed + */ + public function delete($id = null) + { + // + } + + public function index() + { + // + } + } diff --git a/system/Commands/Generators/Views/entity.tpl.php b/system/Commands/Generators/Views/entity.tpl.php index b80ad680cfd4..7c563be4e045 100644 --- a/system/Commands/Generators/Views/entity.tpl.php +++ b/system/Commands/Generators/Views/entity.tpl.php @@ -7,12 +7,10 @@ class {class} extends Entity { protected $datamap = []; - - protected $dates = [ + protected $dates = [ 'created_at', 'updated_at', 'deleted_at', ]; - - protected $casts = []; + protected $casts = []; } diff --git a/system/Commands/Generators/Views/filter.tpl.php b/system/Commands/Generators/Views/filter.tpl.php index 5e2b50e03675..19147bbaec8d 100644 --- a/system/Commands/Generators/Views/filter.tpl.php +++ b/system/Commands/Generators/Views/filter.tpl.php @@ -9,7 +9,19 @@ class {class} implements FilterInterface { /** - * {@inheritdoc} + * Do whatever processing this filter needs to do. + * By default it should not return anything during + * normal execution. However, when an abnormal state + * is found, it should return an instance of + * CodeIgniter\HTTP\Response. If it does, script + * execution will end and that Response will be + * sent back to the client, allowing for error pages, + * redirects, etc. + * + * @param RequestInterface $request + * @param array|null $arguments + * + * @return mixed */ public function before(RequestInterface $request, $arguments = null) { @@ -17,7 +29,16 @@ public function before(RequestInterface $request, $arguments = null) } /** - * {@inheritdoc} + * Allows After filters to inspect and modify the response + * object as needed. This method does not allow any way + * to stop execution of other after filters, short of + * throwing an Exception or Error. + * + * @param RequestInterface $request + * @param ResponseInterface $response + * @param array|null $arguments + * + * @return mixed */ public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) { diff --git a/system/Commands/Generators/Views/migration.tpl.php b/system/Commands/Generators/Views/migration.tpl.php index db0741a56b75..0fecad5888f2 100644 --- a/system/Commands/Generators/Views/migration.tpl.php +++ b/system/Commands/Generators/Views/migration.tpl.php @@ -6,6 +6,31 @@ class {class} extends Migration { + + protected $DBGroup = ''; + + public function up() + { + $this->forge->addField([ + 'id' => ['type' => 'VARCHAR', 'constraint' => 128, 'null' => false], + 'ip_address' => ['type' => 'VARCHAR', 'constraint' => 45, 'null' => false], + 'timestamp' => ['type' => 'INT', 'unsigned' => true, 'null' => false, 'default' => 0], + 'data' => ['type' => 'TEXT', 'null' => false, 'default' => ''], + ]); + + $this->forge->addKey(['id', 'ip_address'], true); + + $this->forge->addKey('id', true); + + $this->forge->addKey('timestamp'); + $this->forge->createTable('', true); + } + + public function down() + { + $this->forge->dropTable('', true); + } + public function up() { // @@ -15,4 +40,5 @@ public function down() { // } + } diff --git a/system/Commands/Generators/Views/model.tpl.php b/system/Commands/Generators/Views/model.tpl.php index 64750de5dd11..255c56dd5d68 100644 --- a/system/Commands/Generators/Views/model.tpl.php +++ b/system/Commands/Generators/Views/model.tpl.php @@ -6,24 +6,22 @@ class {class} extends Model { - protected $table = '{table}'; - protected $primaryKey = 'id'; - protected $useAutoIncrement = true; - - protected $insertID = 0; - protected $DBGroup = '{dbgroup}'; - - protected $returnType = '{return}'; - protected $useSoftDeletes = false; - protected $allowedFields = []; + protected $DBGroup = '{DBGroup}'; + protected $table = '{table}'; + protected $primaryKey = 'id'; + protected $useAutoIncrement = true; + protected $insertID = 0; + protected $returnType = '{return}'; + protected $useSoftDelete = false; + protected $protectFields = true; + protected $allowedFields = []; // Dates - protected $useTimestamps = false; - protected $dateFormat = 'datetime'; - protected $createdField = 'created_at'; - protected $updatedField = 'updated_at'; - protected $deletedField = 'deleted_at'; - protected $protectFields = true; + protected $useTimestamps = false; + protected $dateFormat = 'datetime'; + protected $createdField = 'created_at'; + protected $updatedField = 'updated_at'; + protected $deletedField = 'deleted_at'; // Validation protected $validationRules = []; @@ -32,13 +30,13 @@ class {class} extends Model protected $cleanValidationRules = true; // Callbacks - protected $allowCallbacks = true; - protected $beforeInsert = []; - protected $afterInsert = []; - protected $beforeUpdate = []; - protected $afterUpdate = []; - protected $beforeFind = []; - protected $afterFind = []; - protected $beforeDelete = []; - protected $afterDelete = []; + protected $allowCallbacks = true; + protected $beforeInsert = []; + protected $afterInsert = []; + protected $beforeUpdate = []; + protected $afterUpdate = []; + protected $beforeFind = []; + protected $afterFind = []; + protected $beforeDelete = []; + protected $afterDelete = []; } diff --git a/system/Commands/Generators/Views/seed.tpl.php b/system/Commands/Generators/Views/seeder.tpl.php similarity index 100% rename from system/Commands/Generators/Views/seed.tpl.php rename to system/Commands/Generators/Views/seeder.tpl.php diff --git a/system/Commands/Generators/Views/session_migration.tpl.php b/system/Commands/Generators/Views/session_migration.tpl.php deleted file mode 100644 index 9bcef3dbc552..000000000000 --- a/system/Commands/Generators/Views/session_migration.tpl.php +++ /dev/null @@ -1,54 +0,0 @@ -<@php - -namespace {namespace}; - -use CodeIgniter\Database\Migration; - -class {class} extends Migration -{ - - protected $DBGroup = ''; - - - public function up() - { - $this->forge->addField([ - 'id' => [ - 'type' => 'VARCHAR', - 'constraint' => 128, - 'null' => false, - ], - 'ip_address' => [ - 'type' => 'VARCHAR', - 'constraint' => 45, - 'null' => false, - ], - 'timestamp' => [ - 'type' => 'INT', - 'constraint' => 10, - 'unsigned' => true, - 'null' => false, - 'default' => 0, - ], - 'data' => [ - 'type' => 'TEXT', - 'null' => false, - 'default' => '', - ], - ]); - - $this->forge->addKey(['id', 'ip_address'], true); - - $this->forge->addKey('id', true); - - $this->forge->addKey('timestamp'); - $this->forge->createTable('', true); - } - - //-------------------------------------------------------------------- - - public function down() - { - $this->forge->dropTable('', true); - } -} diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index e0ea75939521..09f9a14b3d7d 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -28,7 +28,7 @@ class Forge extends BaseForge /** * CREATE DATABASE IF statement * - * @todo missing charset, collat & check for existant + * @todo missing charset, collat & check for existent * * @var string */ diff --git a/system/Exceptions/CriticalError.php b/system/Exceptions/CriticalError.php index 23353d21e0b4..c8355721a8ff 100644 --- a/system/Exceptions/CriticalError.php +++ b/system/Exceptions/CriticalError.php @@ -14,7 +14,7 @@ use Error; /** - * Error: Critical conditions, like component unavailble, etc. + * Error: Critical conditions, like component unavailable, etc. */ class CriticalError extends Error { diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index 2ef555fa1521..ef74821ece05 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -444,7 +444,7 @@ protected function processGlobals(string $uri = null) } /** - * Add any method-specific flters to the mix. + * Add any method-specific filters to the mix. * * @return void */ diff --git a/system/Language/en/CLI.php b/system/Language/en/CLI.php index 36a4c09e2cfc..6b0f2dc24d88 100644 --- a/system/Language/en/CLI.php +++ b/system/Language/en/CLI.php @@ -11,20 +11,27 @@ // CLI language settings return [ - 'commandNotFound' => 'Command "{0}" not found.', - 'altCommandSingular' => 'Did you mean this?', 'altCommandPlural' => 'Did you mean one of these?', - 'helpUsage' => 'Usage:', + 'altCommandSingular' => 'Did you mean this?', + 'cancelOperation' => 'Operation has been cancelled.', + 'commandNotFound' => 'Command "{0}" not found.', + 'generator' => [ + 'className' => 'Class name', + 'commandType' => 'Command type', + 'databaseGroup' => 'Database group', + 'fileCreate' => 'File created: {0}', + 'fileError' => 'Error while creating file: {0}', + 'fileExist' => 'File exists: {0}', + 'fileOverwrite' => 'File overwritten: {0}', + 'parentClass' => 'Parent class', + 'returnType' => 'Return type', + 'tableName' => 'Table name', + 'usingCINamespace' => 'Warning: using CodeIgniter namespace will generate file in the system directory.' + ], + 'helpArguments' => 'Arguments:', 'helpDescription' => 'Description:', 'helpOptions' => 'Options:', - 'helpArguments' => 'Arguments:', + 'helpUsage' => 'Usage:', 'invalidColor' => 'Invalid {0} color: {1}.', - - // Generators - 'generateClassName' => 'Name of class', - 'generateParentClass' => 'Name of parent class to extend from', - 'generateFileExists' => '{0} already exists.', - 'generateFileSuccess' => 'Created file: ', - 'generateFileError' => 'Error in creating file: ', 'namespaceNotDefined' => 'Namespace "{0}" is not defined.', -]; +]; \ No newline at end of file diff --git a/tests/_support/Commands/LanguageCommand.php b/tests/_support/Commands/LanguageCommand.php index ca264aa51059..d449deefd787 100644 --- a/tests/_support/Commands/LanguageCommand.php +++ b/tests/_support/Commands/LanguageCommand.php @@ -2,10 +2,14 @@ namespace Tests\Support\Commands; -use CodeIgniter\CLI\GeneratorCommand; +use CodeIgniter\CLI\BaseCommand; +use CodeIgniter\CLI\GeneratorTrait; -class LanguageCommand extends GeneratorCommand +class LanguageCommand extends BaseCommand { + use GeneratorTrait; + + protected $group = 'Generators'; protected $name = 'publish:language'; protected $description = 'Publishes a language file.'; protected $usage = 'publish:language [options]'; @@ -18,19 +22,17 @@ public function run(array $params) { $params[0] = 'Foobar'; $params['lang'] = $params['lang'] ?? 'en'; - $sort = (isset($params['sort']) && $params['sort'] === 'off') ? false : true; - $this->setSortImports($sort); + $this->component = 'Language'; + $this->directory = 'Language\\' . $params['lang']; - parent::run($params); - } + $sort = (isset($params['sort']) && $params['sort'] === 'off') ? false : true; + $this->setSortImports($sort); - protected function getNamespacedClass(string $rootNamespace, string $class): string - { - return $rootNamespace . '\\Language\\' . $this->params['lang'] . '\\' . $class; + $this->execute($params); } - protected function getTemplate(): string + protected function prepare(string $class): string { return file_get_contents(__DIR__ . '/Foobar.php') ?: ''; } diff --git a/tests/system/Commands/CommandGeneratorTest.php b/tests/system/Commands/CommandGeneratorTest.php new file mode 100644 index 000000000000..5aa806d34fd0 --- /dev/null +++ b/tests/system/Commands/CommandGeneratorTest.php @@ -0,0 +1,99 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + $dir = dirname($file); + is_file($file) && unlink($file); + is_dir($dir) && rmdir($dir); + } + + protected function getFileContents(string $filepath): string + { + if (! file_exists($filepath)) + { + return ''; + } + + return file_get_contents($filepath) ?: ''; + } + + public function testGenerateCommand() + { + command('make:command deliver'); + $file = APPPATH . 'Commands/Deliver.php'; + $this->assertFileExists($file); + $contents = $this->getFileContents($file); + $this->assertStringContainsString('protected $group = \'CodeIgniter\';', $contents); + $this->assertStringContainsString('protected $name = \'command:name\';', $contents); + } + + public function testGenerateCommandWithOptionCommand() + { + command('make:command deliver -command clear:sessions'); + $file = APPPATH . 'Commands/Deliver.php'; + $this->assertFileExists($file); + $contents = $this->getFileContents($file); + $this->assertStringContainsString('protected $name = \'clear:sessions\';', $contents); + $this->assertStringContainsString('protected $usage = \'clear:sessions [arguments] [options]\';', $contents); + } + + public function testGenerateCommandWithOptionTypeBasic() + { + command('make:command deliver -type basic'); + $file = APPPATH . 'Commands/Deliver.php'; + $this->assertFileExists($file); + $contents = $this->getFileContents($file); + $this->assertStringContainsString('protected $group = \'CodeIgniter\';', $contents); + $this->assertStringContainsString('protected $name = \'command:name\';', $contents); + } + + public function testGenerateCommandWithOptionTypeGenerator() + { + command('make:command deliver -type generator'); + $file = APPPATH . 'Commands/Deliver.php'; + $this->assertFileExists($file); + $contents = $this->getFileContents($file); + $this->assertStringContainsString('protected $group = \'Generators\';', $contents); + $this->assertStringContainsString('protected $name = \'command:name\';', $contents); + } + + public function testGenerateCommandWithOptionGroup() + { + command('make:command deliver -group Deliverables'); + $file = APPPATH . 'Commands/Deliver.php'; + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertFileExists($file); + + $contents = $this->getFileContents($file); + $this->assertStringContainsString('protected $group = \'Deliverables\';', $contents); + } + + public function testGenerateCommandWithOptionSuffix() + { + command('make:command publish -suffix'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Commands/PublishCommand.php'; + $this->assertFileExists($file); + } +} diff --git a/tests/system/Commands/ConfigGeneratorTest.php b/tests/system/Commands/ConfigGeneratorTest.php new file mode 100644 index 000000000000..f4704641f4b4 --- /dev/null +++ b/tests/system/Commands/ConfigGeneratorTest.php @@ -0,0 +1,40 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + is_file($file) && unlink($file); + } + + public function testGenerateConfig() + { + command('make:config auth'); + $this->assertFileExists(APPPATH . 'Config/Auth.php'); + } + + public function testGenerateConfigWithOptionSuffix() + { + command('make:config auth -suffix'); + $this->assertFileExists(APPPATH . 'Config/AuthConfig.php'); + } +} diff --git a/tests/system/Commands/ConfigurableSortImportsTest.php b/tests/system/Commands/ConfigurableSortImportsTest.php index 16d2d1fe9944..8b9c96f9e1ac 100644 --- a/tests/system/Commands/ConfigurableSortImportsTest.php +++ b/tests/system/Commands/ConfigurableSortImportsTest.php @@ -14,8 +14,9 @@ protected function setUp(): void parent::setUp(); CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + + $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); } protected function tearDown(): void @@ -23,11 +24,10 @@ protected function tearDown(): void parent::tearDown(); stream_filter_remove($this->streamFilter); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = trim(substr($result, 14)); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $file); + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); $dir = dirname($file); - file_exists($file) && unlink($file); + is_file($file) && unlink($file); is_dir($dir) && rmdir($dir); } @@ -36,17 +36,17 @@ public function testEnabledSortImportsWillDisruptLanguageFilePublish() command('publish:language --lang es'); $file = APPPATH . 'Language/es/Foobar.php'; - $this->assertStringContainsString('Created file: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); $this->assertFileExists($file); $this->assertNotSame(sha1_file(SUPPORTPATH . 'Commands/Foobar.php'), sha1_file($file)); } public function testDisabledSortImportsWillNotAffectLanguageFilesPublish() { - command('publish:language --lang es --sort off'); + command('publish:language --lang ar --sort off'); - $file = APPPATH . 'Language/es/Foobar.php'; - $this->assertStringContainsString('Created file: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Language/ar/Foobar.php'; + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); $this->assertFileExists($file); $this->assertSame(sha1_file(SUPPORTPATH . 'Commands/Foobar.php'), sha1_file($file)); } diff --git a/tests/system/Commands/ControllerGeneratorTest.php b/tests/system/Commands/ControllerGeneratorTest.php new file mode 100644 index 000000000000..f69cc209b97e --- /dev/null +++ b/tests/system/Commands/ControllerGeneratorTest.php @@ -0,0 +1,82 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + is_file($file) && unlink($file); + } + + protected function getFileContents(string $filepath): string + { + if (! file_exists($filepath)) + { + return ''; + } + + return file_get_contents($filepath) ?: ''; + } + + public function testGenerateController() + { + command('make:controller user'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Controllers/User.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('extends BaseController', $this->getFileContents($file)); + } + + public function testGenerateControllerWithOptionBare() + { + command('make:controller blog -bare'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Controllers/Blog.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('extends Controller', $this->getFileContents($file)); + + } + + public function testGenerateControllerWithOptionRestful() + { + command('make:controller order -restful'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Controllers/Order.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('extends ResourceController', $this->getFileContents($file)); + } + + public function testGenerateControllerWithOptionRestfulPresenter() + { + command('make:controller pay -restful presenter'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Controllers/Pay.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('extends ResourcePresenter', $this->getFileContents($file)); + } + + public function testGenerateControllerWithOptionSuffix() + { + command('make:controller dashboard -suffix'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertFileExists(APPPATH . 'Controllers/DashboardController.php'); + } +} diff --git a/tests/system/Commands/CreateCommandTest.php b/tests/system/Commands/CreateCommandTest.php deleted file mode 100644 index 491f801b562f..000000000000 --- a/tests/system/Commands/CreateCommandTest.php +++ /dev/null @@ -1,96 +0,0 @@ -streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = trim(substr($result, 14)); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $file); - $dir = dirname($file); - file_exists($file) && unlink($file); - is_dir($dir) && rmdir($dir); - } - - protected function getBuffer(): string - { - return CITestStreamFilter::$buffer; - } - - protected function getFileContents(string $filepath): string - { - if (! file_exists($filepath)) - { - return ''; - } - - $contents = file_get_contents($filepath); - - return $contents ?: ''; - } - - public function testCreateCommandWithDefaults() - { - command('make:command deliver'); - - $file = APPPATH . 'Commands/Deliver.php'; - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertFileExists($file); - - $contents = $this->getFileContents($file); - $this->assertStringContainsString('use CodeIgniter\\CLI\\BaseCommand;', $contents); - $this->assertStringContainsString('extends BaseCommand', $contents); - $this->assertStringContainsString('protected $group = \'CodeIgniter\';', $contents); - $this->assertStringContainsString('protected $name = \'command:name\';', $contents); - $this->assertStringContainsString('protected $usage = \'command:name [arguments] [options]\';', $contents); - $this->assertStringContainsString('public function run(array $params)', $contents); - } - - public function testCreateCommandWithGivenOptions() - { - command('make:command deliver -command make:deliver -type generator'); - $file = APPPATH . 'Commands/Deliver.php'; - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertFileExists($file); - - $contents = $this->getFileContents($file); - $this->assertStringContainsString('use CodeIgniter\\CLI\\GeneratorCommand;', $contents); - $this->assertStringContainsString('extends GeneratorCommand', $contents); - $this->assertStringNotContainsString('protected $group = \'Generators\';', $contents); - $this->assertStringContainsString('protected $name = \'make:deliver\';', $contents); - $this->assertStringContainsString('protected $usage = \'make:deliver [arguments] [options]\';', $contents); - $this->assertStringContainsString('protected function getTemplate(): string', $contents); - } - - public function testCreateCommandWithOverridingGroupGiven() - { - command('make:command deliver -command make:deliver -type generator -group Deliverables'); - $file = APPPATH . 'Commands/Deliver.php'; - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertFileExists($file); - - $contents = $this->getFileContents($file); - $this->assertStringContainsString('use CodeIgniter\\CLI\\GeneratorCommand;', $contents); - $this->assertStringContainsString('extends GeneratorCommand', $contents); - $this->assertStringContainsString('protected $group = \'Deliverables\';', $contents); - $this->assertStringContainsString('protected $name = \'make:deliver\';', $contents); - $this->assertStringContainsString('protected $usage = \'make:deliver [arguments] [options]\';', $contents); - $this->assertStringContainsString('protected function getTemplate(): string', $contents); - } -} diff --git a/tests/system/Commands/CreateControllerTest.php b/tests/system/Commands/CreateControllerTest.php deleted file mode 100644 index d49aeabd32e6..000000000000 --- a/tests/system/Commands/CreateControllerTest.php +++ /dev/null @@ -1,103 +0,0 @@ -streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = trim(substr($result, 14)); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $file); - file_exists($file) && unlink($file); - } - - protected function getBuffer(): string - { - return CITestStreamFilter::$buffer; - } - - protected function getFileContents(string $filepath): string - { - if (! file_exists($filepath)) - { - return ''; - } - - $contents = file_get_contents($filepath); - - return $contents ?: ''; - } - - public function testCreateControllerThatUsesBaseController() - { - command('make:controller user'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('User.php', $this->getBuffer()); - $this->assertFileExists(APPPATH . 'Controllers/User.php'); - $this->assertStringContainsString('BaseController', $this->getFileContents(APPPATH . 'Controllers/User.php')); - } - - public function testCreateControllerThatUsesCodeigniterController() - { - command('make:controller blog -bare'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('Blog.php', $this->getBuffer()); - $this->assertFileExists(APPPATH . 'Controllers/Blog.php'); - $this->assertStringContainsString('use CodeIgniter\Controller;', $this->getFileContents(APPPATH . 'Controllers/Blog.php')); - } - - public function testCreateControllerThatUsesDefaultRestfulResource() - { - command('make:controller api -restful'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('Api.php', $this->getBuffer()); - $this->assertFileExists(APPPATH . 'Controllers/Api.php'); - $this->assertStringContainsString('use CodeIgniter\RESTful\ResourceController;', $this->getFileContents(APPPATH . 'Controllers/Api.php')); - } - - public function testCreateControllerThatUsesAGivenRestfulResource() - { - command('make:controller api -restful presenter'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('Api.php', $this->getBuffer()); - $this->assertFileExists(APPPATH . 'Controllers/Api.php'); - $this->assertStringContainsString('use CodeIgniter\RESTful\ResourcePresenter;', $this->getFileContents(APPPATH . 'Controllers/Api.php')); - } - - public function testCreateRestfulControllerHasRestfulMethods() - { - command('make:controller pay -restful'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('Pay.php', $this->getBuffer()); - $this->assertFileExists(APPPATH . 'Controllers/Pay.php'); - $this->assertStringContainsString('public function new()', $this->getFileContents(APPPATH . 'Controllers/Pay.php')); - } - - public function testCreateControllerCanCreateControllersInSubfolders() - { - command('make:controller admin/user'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('User.php', $this->getBuffer()); - $this->assertDirectoryExists(APPPATH . 'Controllers/Admin'); - $this->assertFileExists(APPPATH . 'Controllers/Admin/User.php'); - - // cleanup - unlink(APPPATH . 'Controllers/Admin/User.php'); - rmdir(APPPATH . 'Controllers/Admin'); - } -} diff --git a/tests/system/Commands/CreateEntityTest.php b/tests/system/Commands/CreateEntityTest.php deleted file mode 100644 index ccbd43f1d0ef..000000000000 --- a/tests/system/Commands/CreateEntityTest.php +++ /dev/null @@ -1,66 +0,0 @@ -streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - } - - protected function getBuffer(): string - { - return CITestStreamFilter::$buffer; - } - - protected function getFileContents(string $filepath): string - { - if (! file_exists($filepath)) - { - return ''; - } - - $contents = file_get_contents($filepath); - - return $contents ?: ''; - } - - public function testCreateEntityCreatesASkeletonEntityFile() - { - command('make:entity user'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('User.php', $this->getBuffer()); - $this->assertFileExists(APPPATH . 'Entities/User.php'); - $this->assertStringContainsString('use CodeIgniter\\Entity;', $this->getFileContents(APPPATH . 'Entities/User.php')); - - // cleanup - unlink(APPPATH . 'Entities/User.php'); - rmdir(APPPATH . 'Entities'); - } - - public function testCreateEntityCreatesInOtherNamespace() - { - command('make:entity user -n CodeIgniter'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('User.php', $this->getBuffer()); - $this->assertFileExists(SYSTEMPATH . 'Entities/User.php'); - $this->assertStringContainsString('use CodeIgniter\\Entity;', $this->getFileContents(SYSTEMPATH . 'Entities/User.php')); - - // cleanup - unlink(SYSTEMPATH . 'Entities/User.php'); - rmdir(SYSTEMPATH . 'Entities'); - } -} diff --git a/tests/system/Commands/CreateFilterTest.php b/tests/system/Commands/CreateFilterTest.php deleted file mode 100644 index f30f12973db5..000000000000 --- a/tests/system/Commands/CreateFilterTest.php +++ /dev/null @@ -1,41 +0,0 @@ -streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = trim(substr($result, 14)); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $file); - file_exists($file) && unlink($file); - } - - protected function getBuffer(): string - { - return CITestStreamFilter::$buffer; - } - - public function testCreateFilterWorks() - { - command('make:filter admin'); - - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertFileExists(APPPATH . 'Filters/Admin.php'); - } -} diff --git a/tests/system/Commands/CreateMigrationTest.php b/tests/system/Commands/CreateMigrationTest.php deleted file mode 100644 index ff04e410df30..000000000000 --- a/tests/system/Commands/CreateMigrationTest.php +++ /dev/null @@ -1,84 +0,0 @@ -streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = trim(substr($result, 14)); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $file); - file_exists($file) && unlink($file); - } - - protected function getBuffer(): string - { - return CITestStreamFilter::$buffer; - } - - public function testCreateMigration() - { - command('make:migration databaseMigrator'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('_DatabaseMigrator.php', $this->getBuffer()); - } - - public function testCreateMigrationFailsOnUnwritableDirectory() - { - if ('\\' === DIRECTORY_SEPARATOR) - { - $this->markTestSkipped('chmod does not work as expected on Windows'); - } - - chmod(APPPATH . 'Database/Migrations', 0444); - - command('make:migration migrateOne'); - $this->assertStringContainsString('Error in creating file: ', $this->getBuffer()); - - chmod(APPPATH . 'Database/Migrations', 0755); - } - - public function testCreateMigrationFailOnUndefinedNamespace() - { - try - { - command('make:migration migrateTwo -n CodeIgnite'); - } - catch (\Throwable $e) - { - ob_end_clean(); - $this->assertInstanceOf('RuntimeException', $e); - $this->assertEquals('Namespace "CodeIgnite" is not defined.', $e->getMessage()); - } - } - - public function testCreateMigrationOnOtherNamespace() - { - command('make:migration migrateThree -n CodeIgniter'); - $this->assertStringContainsString('Created file:', $this->getBuffer()); - $this->assertStringContainsString('SYSTEMPATH', $this->getBuffer()); - - // cleanup - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = trim(substr($result, 14)); - $file = str_replace('SYSTEMPATH' . DIRECTORY_SEPARATOR, SYSTEMPATH, $file); - $dir = dirname($file); - file_exists($file) && unlink($file); - rmdir($dir); - } -} diff --git a/tests/system/Commands/CreateModelTest.php b/tests/system/Commands/CreateModelTest.php deleted file mode 100644 index d1251b68aba3..000000000000 --- a/tests/system/Commands/CreateModelTest.php +++ /dev/null @@ -1,98 +0,0 @@ -streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = trim(substr($result, 14)); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $file); - file_exists($file) && unlink($file); - } - - protected function getBuffer(): string - { - return CITestStreamFilter::$buffer; - } - - protected function getFileContents(string $filepath): string - { - if (! file_exists($filepath)) - { - return ''; - } - - $contents = file_get_contents($filepath); - - return $contents ?: ''; - } - - public function testCreateModelWithDefaults() - { - command('make:model user'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - - $file = APPPATH . 'Models/User.php'; - $this->assertFileExists($file); - $this->assertStringContainsString('extends Model', $this->getFileContents($file)); - $this->assertStringContainsString('protected $table = \'users\';', $this->getFileContents($file)); - $this->assertStringContainsString('protected $DBGroup = \'default\';', $this->getFileContents($file)); - $this->assertStringContainsString('protected $returnType = \'array\';', $this->getFileContents($file)); - } - - public function testCreateModelWithDbGroup() - { - command('make:model user -dbgroup testing'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - - $file = APPPATH . 'Models/User.php'; - $this->assertFileExists($file); - $this->assertStringContainsString('protected $DBGroup = \'testing\';', $this->getFileContents($file)); - } - - public function testCreateModelWithEntityAsReturnType() - { - command('make:model user -entity'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - - $file = APPPATH . 'Models/User.php'; - $this->assertFileExists($file); - $this->assertStringContainsString('protected $returnType = \'App\\Entities\\User\';', $this->getFileContents($file)); - } - - public function testCreateModelWithDifferentModelTable() - { - command('make:model user -table utilisateur'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - - $file = APPPATH . 'Models/User.php'; - $this->assertFileExists($file); - $this->assertStringContainsString('protected $table = \'utilisateurs\';', $this->getFileContents($file)); - } - - public function testCreateModelWithEntityAndNameHasModelWillTrimInEntity() - { - command('make:model userModel -entity'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - - $file = APPPATH . 'Models/UserModel.php'; - $this->assertFileExists($file); - $this->assertStringContainsString('protected $returnType = \'App\\Entities\\User\';', $this->getFileContents($file)); - } -} diff --git a/tests/system/Commands/CreateScaffoldTest.php b/tests/system/Commands/CreateScaffoldTest.php deleted file mode 100644 index 3e00c35782b1..000000000000 --- a/tests/system/Commands/CreateScaffoldTest.php +++ /dev/null @@ -1,149 +0,0 @@ -streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - } - - protected function getBuffer(): string - { - return CITestStreamFilter::$buffer; - } - - protected function getFileContents(string $filepath): string - { - if (! file_exists($filepath)) - { - return ''; - } - - $contents = file_get_contents($filepath); - - return $contents ?: ''; - } - - public function testCreateScaffoldProducesManyFiles() - { - command('make:scaffold people'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - - $dir = '\\' . DIRECTORY_SEPARATOR; - $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; - preg_match('/' . $migration . '/u', $this->getBuffer(), $matches); - $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); - - $paths = [ - 'Controllers', - 'Models', - 'Entities', - ]; - - foreach ($paths as $path) - { - $this->assertFileExists(APPPATH . $path . '/People.php'); - } - $this->assertFileExists($matches[0]); - $this->assertFileExists(APPPATH . 'Database/Seeds/People.php'); - - // cleanup - foreach ($paths as $path) - { - unlink(APPPATH . $path . '/People.php'); - } - unlink($matches[0]); - unlink(APPPATH . 'Database/Seeds/People.php'); - rmdir(APPPATH . 'Entities'); - } - - public function testCreateScaffoldWithOneOptionPassed() - { - command('make:scaffold fixer -bare'); - - $dir = '\\' . DIRECTORY_SEPARATOR; - $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; - preg_match('/' . $migration . '/u', $this->getBuffer(), $matches); - $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); - - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - - // File existence check - $paths = [ - 'Controllers', - 'Models', - 'Entities', - ]; - foreach ($paths as $path) - { - $this->assertFileExists(APPPATH . $path . '/Fixer.php'); - } - $this->assertFileExists($matches[0]); - $this->assertFileExists(APPPATH . 'Database/Seeds/Fixer.php'); - - // Options check - $this->assertStringContainsString('extends Controller', $this->getFileContents(APPPATH . 'Controllers/Fixer.php')); - - // cleanup - foreach ($paths as $path) - { - unlink(APPPATH . $path . '/Fixer.php'); - } - unlink($matches[0]); - unlink(APPPATH . 'Database/Seeds/Fixer.php'); - rmdir(APPPATH . 'Entities'); - } - - public function testCreateScaffoldCanPassManyOptionsToCommands() - { - command('make:scaffold user -restful -dbgroup testing -force -table utilisateur'); - - $dir = '\\' . DIRECTORY_SEPARATOR; - $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; - preg_match('/' . $migration . '/u', $this->getBuffer(), $matches); - $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); - - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - - // File existence check - $paths = [ - 'Controllers', - 'Models', - 'Entities', - ]; - foreach ($paths as $path) - { - $this->assertFileExists(APPPATH . $path . '/User.php'); - } - $this->assertFileExists($matches[0]); - $this->assertFileExists(APPPATH . 'Database/Seeds/User.php'); - - // Options check - $this->assertStringContainsString('extends ResourceController', $this->getFileContents(APPPATH . 'Controllers/User.php')); - $this->assertStringContainsString('protected $table = \'utilisateurs\';', $this->getFileContents(APPPATH . 'Models/User.php')); - $this->assertStringContainsString('protected $DBGroup = \'testing\';', $this->getFileContents(APPPATH . 'Models/User.php')); - - // cleanup - foreach ($paths as $path) - { - unlink(APPPATH . $path . '/User.php'); - } - unlink($matches[0]); - unlink(APPPATH . 'Database/Seeds/User.php'); - rmdir(APPPATH . 'Entities'); - } -} diff --git a/tests/system/Commands/CreateSeederTest.php b/tests/system/Commands/CreateSeederTest.php deleted file mode 100644 index 538ffd342e60..000000000000 --- a/tests/system/Commands/CreateSeederTest.php +++ /dev/null @@ -1,55 +0,0 @@ -streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = trim(substr($result, 14)); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $file); - file_exists($file) && unlink($file); - } - - protected function getBuffer(): string - { - return CITestStreamFilter::$buffer; - } - - public function testCreateSeederCommand() - { - command('make:seeder testSeeder'); - - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - $this->assertStringContainsString('TestSeeder.php', $this->getBuffer()); - } - - public function testCreateSeederFailsOnDuplicateFile() - { - command('make:seeder seedOne'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - CITestStreamFilter::$buffer = ''; - - command('make:seeder seedOne'); - $this->assertStringContainsString('SeedOne.php already exists.', $this->getBuffer()); - CITestStreamFilter::$buffer = ''; - - command('make:seeder seedOne -force'); - $this->assertStringContainsString('Created file: ', $this->getBuffer()); - } -} diff --git a/tests/system/Commands/EntityGeneratoTest.php b/tests/system/Commands/EntityGeneratoTest.php new file mode 100644 index 000000000000..701548b80861 --- /dev/null +++ b/tests/system/Commands/EntityGeneratoTest.php @@ -0,0 +1,42 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + $dir = dirname($file); + is_file($file) && unlink($file); + is_dir($dir) && rmdir($dir); + } + + public function testGenerateEntity() + { + command('make:entity user'); + $this->assertFileExists(APPPATH . 'Entities/User.php'); + } + + public function testGenerateEntityWithOptionSuffix() + { + command('make:entity user -suffix'); + $this->assertFileExists(APPPATH . 'Entities/UserEntity.php'); + } +} diff --git a/tests/system/Commands/FilterGeneratorTest.php b/tests/system/Commands/FilterGeneratorTest.php new file mode 100644 index 000000000000..140949b71436 --- /dev/null +++ b/tests/system/Commands/FilterGeneratorTest.php @@ -0,0 +1,40 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + is_file($file) && unlink($file); + } + + public function testGenerateFilter() + { + command('make:filter admin'); + $this->assertFileExists(APPPATH . 'Filters/Admin.php'); + } + + public function testGenerateFilterWithOptionSuffix() + { + command('make:filter admin -suffix'); + $this->assertFileExists(APPPATH . 'Filters/AdminFilter.php'); + } +} diff --git a/tests/system/Commands/GeneratorsTest.php b/tests/system/Commands/GeneratorsTest.php new file mode 100644 index 000000000000..f2bf380d0ab2 --- /dev/null +++ b/tests/system/Commands/GeneratorsTest.php @@ -0,0 +1,86 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + } + + public function testGenerateFileCreated() + { + command('make:seeder categories'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Database/Seeds/Categories.php'; + is_file($file) && unlink($file); + } + + public function testGenerateFileExists() + { + command('make:filter items'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + CITestStreamFilter::$buffer = ''; + command('make:filter items'); + $this->assertStringContainsString('File exists: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Filters/Items.php'; + is_file($file) && unlink($file); + } + + public function testGenerateFileOverwritten() + { + command('make:controller products'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + CITestStreamFilter::$buffer = ''; + command('make:controller products -force'); + $this->assertStringContainsString('File overwritten: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Controllers/Products.php'; + is_file($file) && unlink($file); + } + + public function testGenerateFileFailsOnUnwritableDirectory() + { + if ('\\' === DIRECTORY_SEPARATOR) + { + $this->markTestSkipped('chmod does not work as expected on Windows'); + } + + chmod(APPPATH . 'Filters', 0444); + + command('make:filter permissions'); + $this->assertStringContainsString('Error while creating file: ', CITestStreamFilter::$buffer); + + chmod(APPPATH . 'Filters', 0755); + } + + public function testGenerateFailsOnUndefinedNamespace() + { + command('make:model cars -namespace CodeIgnite'); + $this->assertStringContainsString('Namespace "CodeIgnite" is not defined.', CITestStreamFilter::$buffer); + } + + public function testGenerateFileInSubfolders() + { + command('make:controller admin/user'); + $file = APPPATH . 'Controllers/Admin/User.php'; + $dir = dirname($file); + $this->assertFileExists($file); + $this->assertDirectoryExists($dir); + is_file($file) && unlink($file); + is_dir($dir) && rmdir($dir); + } +} diff --git a/tests/system/Commands/MigrationGeneratorTest.php b/tests/system/Commands/MigrationGeneratorTest.php new file mode 100644 index 000000000000..827c104157e6 --- /dev/null +++ b/tests/system/Commands/MigrationGeneratorTest.php @@ -0,0 +1,52 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + file_exists($file) && unlink($file); + } + + public function testGenerateMigration() + { + command('make:migration database'); + $this->assertStringContainsString('_Database.php', CITestStreamFilter::$buffer); + } + + public function testGenerateMigrationWithOptionSession() + { + command('make:migration -session'); + $this->assertStringContainsString('_CreateCiSessionsTable.php', CITestStreamFilter::$buffer); + } + + public function testGenerateMigrationWithOptionTable() + { + command('make:migration -session -table logger'); + $this->assertStringContainsString('_CreateLoggerTable.php', CITestStreamFilter::$buffer); + } + + public function testGenerateMigrationWithOptionSuffix() + { + command('make:migration database -suffix'); + $this->assertStringContainsString('_DatabaseMigration.php', CITestStreamFilter::$buffer); + } +} diff --git a/tests/system/Commands/ModelGeneratorTest.php b/tests/system/Commands/ModelGeneratorTest.php new file mode 100644 index 000000000000..0e3280591b04 --- /dev/null +++ b/tests/system/Commands/ModelGeneratorTest.php @@ -0,0 +1,107 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + is_file($file) && unlink($file); + } + + protected function getFileContent(string $filepath): string + { + if (! is_file($filepath)) + { + return ''; + } + + return file_get_contents($filepath) ?: ''; + } + + public function testGenerateModel() + { + command('make:model user -table users'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Models/User.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('extends Model', $this->getFileContent($file)); + $this->assertStringContainsString('protected $table = \'users\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $DBGroup = \'default\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $returnType = \'array\';', $this->getFileContent($file)); + } + + public function testGenerateModelWithOptionTable() + { + command('make:model cars -table utilisateur'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Models/Cars.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('protected $table = \'utilisateur\';', $this->getFileContent($file)); + } + + public function testGenerateModelWithOptionDBGroup() + { + command('make:model user -dbgroup testing'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Models/User.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('protected $DBGroup = \'testing\';', $this->getFileContent($file)); + } + + public function testGenerateModelWithOptionReturnArray() + { + command('make:model user -return array'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Models/User.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('protected $returnType = \'array\';', $this->getFileContent($file)); + } + + public function testGenerateModelWithOptionReturnObject() + { + command('make:model user -return object'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Models/User.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('protected $returnType = \'object\';', $this->getFileContent($file)); + } + + public function testGenerateModelWithOptionReturnEntity() + { + command('make:model user -return entity'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Models/User.php'; + $this->assertFileExists($file); + $this->assertStringContainsString('protected $returnType = \'App\Entities\User\';', $this->getFileContent($file)); + is_file($file) && unlink($file); + $file = APPPATH . 'Entities/User.php'; + $this->assertFileExists($file); + $dir = dirname($file); + is_file($file) && unlink($file); + is_dir($dir) && rmdir($dir); + } + + public function testGenerateModelWithOptionSuffix() + { + command('make:model user -suffix'); + $this->assertFileExists(APPPATH . 'Models/UserModel.php'); + } +} diff --git a/tests/system/Commands/ScaffoldGeneratorTest.php b/tests/system/Commands/ScaffoldGeneratorTest.php new file mode 100644 index 000000000000..ebf79bbab667 --- /dev/null +++ b/tests/system/Commands/ScaffoldGeneratorTest.php @@ -0,0 +1,112 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + } + + protected function getFileContents(string $filepath): string + { + if (! file_exists($filepath)) + { + return ''; + } + + return file_get_contents($filepath) ?: ''; + } + + public function testCreateScaffoldProducesManyFiles() + { + command('make:scaffold people'); + + $dir = '\\' . DIRECTORY_SEPARATOR; + $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; + preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); + $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); + + // Files check + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertFileExists(APPPATH . 'Controllers/People.php'); + $this->assertFileExists(APPPATH . 'Models/People.php'); + $this->assertStringContainsString('_People.php', CITestStreamFilter::$buffer); + $this->assertFileExists(APPPATH . 'Database/Seeds/People.php'); + + // Options check + unlink(APPPATH . 'Controllers/People.php'); + unlink(APPPATH . 'Models/People.php'); + unlink($matches[0]); + unlink(APPPATH . 'Database/Seeds/People.php'); + } + + public function testCreateScaffoldWithOneOption() + { + command('make:scaffold fixer -bare'); + + $dir = '\\' . DIRECTORY_SEPARATOR; + $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; + preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); + $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); + + // Files check + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertFileExists(APPPATH . 'Controllers/Fixer.php'); + $this->assertFileExists(APPPATH . 'Models/Fixer.php'); + $this->assertStringContainsString('_Fixer.php', CITestStreamFilter::$buffer); + $this->assertFileExists(APPPATH . 'Database/Seeds/Fixer.php'); + + // Options check + $this->assertStringContainsString('extends Controller', $this->getFileContents(APPPATH . 'Controllers/Fixer.php')); + + // Clean up + unlink(APPPATH . 'Controllers/Fixer.php'); + unlink(APPPATH . 'Models/Fixer.php'); + unlink($matches[0]); + unlink(APPPATH . 'Database/Seeds/Fixer.php'); + } + + public function testCreateScaffoldWithManyOptions() + { + command('make:scaffold user -restful -return entity -suffix'); + + $dir = '\\' . DIRECTORY_SEPARATOR; + $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; + preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); + $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); + + // Files check + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertFileExists(APPPATH . 'Controllers/UserController.php'); + $this->assertFileExists(APPPATH . 'Models/UserModel.php'); + $this->assertFileExists(APPPATH . 'Entities/UserEntity.php'); + $this->assertStringContainsString('_UserMigration.php', CITestStreamFilter::$buffer); + $this->assertFileExists(APPPATH . 'Database/Seeds/UserSeeder.php'); + + // Options check + $this->assertStringContainsString('extends ResourceController', $this->getFileContents(APPPATH . 'Controllers/UserController.php')); + + // Clean up + unlink(APPPATH . 'Controllers/UserController.php'); + unlink(APPPATH . 'Models/UserModel.php'); + unlink(APPPATH . 'Entities/UserEntity.php'); + unlink($matches[0]); + unlink(APPPATH . 'Database/Seeds/UserSeeder.php'); + rmdir(APPPATH . 'Entities'); + } +} diff --git a/tests/system/Commands/SeederGeneratorTest.php b/tests/system/Commands/SeederGeneratorTest.php new file mode 100644 index 000000000000..91991aad4f58 --- /dev/null +++ b/tests/system/Commands/SeederGeneratorTest.php @@ -0,0 +1,42 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + stream_filter_remove($this->streamFilter); + + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + file_exists($file) && unlink($file); + } + + public function testGenerateSeeder() + { + command('make:seeder cars'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertFileExists(APPPATH . 'Database/Seeds/Cars.php'); + } + + public function testGenerateSeederWithOptionSuffix() + { + command('make:seeder cars -suffix'); + $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertFileExists(APPPATH . 'Database/Seeds/CarsSeeder.php'); + } +} diff --git a/tests/system/Commands/SessionsCommandsTest.php b/tests/system/Commands/SessionsCommandsTest.php index 2e79ed8c8d8e..14d0fdf4421e 100644 --- a/tests/system/Commands/SessionsCommandsTest.php +++ b/tests/system/Commands/SessionsCommandsTest.php @@ -1,4 +1,6 @@ -streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + + $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); } public function tearDown(): void { stream_filter_remove($this->streamFilter); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = trim(substr($result, 14)); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $file); + $result = str_replace(["\033[1;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); file_exists($file) && unlink($file); } public function testCreateMigrationCommand() { command('session:migration'); - $result = CITestStreamFilter::$buffer; // make sure we end up with a migration class in the right place // or at least that we claim to have done so // separate assertions avoid console color codes - $this->assertStringContainsString('Created file:', $result); - $this->assertStringContainsString('_CreateCiSessionsTable.php', $result); + $this->assertStringContainsString('_CreateCiSessionsTable.php', CITestStreamFilter::$buffer); } public function testOverriddenCreateMigrationCommand() { command('session:migration -t mygoodies'); - $result = CITestStreamFilter::$buffer; // make sure we end up with a migration class in the right place - $this->assertStringContainsString('Created file:', $result); - $this->assertStringContainsString('_CreateMygoodiesTable.php', $result); + $this->assertStringContainsString('_CreateMygoodiesTable.php', CITestStreamFilter::$buffer); } public function testCannotWriteFileOnCreateMigrationCommand() @@ -58,9 +56,8 @@ public function testCannotWriteFileOnCreateMigrationCommand() chmod(APPPATH . 'Database/Migrations', 0444); command('session:migration'); - $this->assertStringContainsString('Error in creating file:', CITestStreamFilter::$buffer); + $this->assertStringContainsString('Error while creating file:', CITestStreamFilter::$buffer); chmod(APPPATH . 'Database/Migrations', 0755); } - }