diff options
| author | David Siegfried <david.siegfried@uni-vechta.de> | 2024-09-03 13:01:52 +0000 |
|---|---|---|
| committer | Jan-Hendrik Willms <tleilax+studip@gmail.com> | 2024-09-03 13:01:52 +0000 |
| commit | 9e8c92f415e5106ee9f726b1c7e251924a7769c9 (patch) | |
| tree | 750e0d1a84f9b4830505d3fdd9992f0e49f14fff /cli/Commands | |
| parent | c5fd2ec69e7f181497a0bf4a3d03e3df465cae9a (diff) | |
add migration-maker, closes #3806
Closes #3806
Merge request studip/studip!3358
Diffstat (limited to 'cli/Commands')
| -rw-r--r-- | cli/Commands/Make/Migration.php | 108 | ||||
| -rw-r--r-- | cli/Commands/Make/Model.php | 125 | ||||
| -rw-r--r-- | cli/Commands/Make/StudipClassPrinter.php | 18 |
3 files changed, 251 insertions, 0 deletions
diff --git a/cli/Commands/Make/Migration.php b/cli/Commands/Make/Migration.php new file mode 100644 index 0000000..d9ae1d1 --- /dev/null +++ b/cli/Commands/Make/Migration.php @@ -0,0 +1,108 @@ +<?php + +namespace Studip\Cli\Commands\Make; + +use Nette\PhpGenerator\PhpFile; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +final class Migration extends Command +{ + private const DEFAULT_BRANCH = '0'; + + protected static $defaultName = 'make:migration'; + + protected function configure(): void + { + $this->setDescription('Create a new migration file'); + $this->addArgument('name', InputArgument::REQUIRED, 'The name of the migration'); + $this->addOption( + 'branch', + 'b', + InputOption::VALUE_OPTIONAL, + 'The branch of the migration file', + self::DEFAULT_BRANCH + ); + $this->addOption('domain', 'd', InputOption::VALUE_OPTIONAL, 'The domain of the migration file', 'studip'); + + $defaultPath = $GLOBALS['STUDIP_BASE_PATH'] . '/db/migrations'; + $this->addOption( + 'path', + 'p', + InputOption::VALUE_OPTIONAL, + 'The location where the migration file should be created', + $defaultPath + ); + $this->addOption( + 'description', + 'D', + InputOption::VALUE_OPTIONAL, + 'The description for the migration', + '' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $branch = $input->getOption('branch'); + $domain = $input->getOption('domain'); + $name = $input->getArgument('name'); + $path = $input->getOption('path'); + $description = $input->getOption('description'); + $verbose = $input->getOption('verbose'); + + $version = $this->getNextMigrationVersion($branch, $domain, $path, $verbose); + $filename = $this->createMigrationFile($path, $version, $name, $description); + + if ($verbose) { + $output->writeln('Migration file ' . $filename . ' created.'); + } + + return Command::SUCCESS; + } + + private function getNextMigrationVersion(string $branch, string $domain, string $path, bool $verbose): string + { + $version = new \DBSchemaVersion($domain, $branch); + $migrator = new \Migrator($path, $version, $verbose); + $topVersions = $migrator->topVersion(true); + + if ($branch === self::DEFAULT_BRANCH) { + $branches = array_keys($topVersions); + usort($branches, 'version_compare'); + $branch = array_pop($branches); + } + + return sprintf('%s.%s', $branch, isset($topVersions[$branch]) ? $topVersions[$branch] + 1 : 1); + } + + private function createMigrationFile(string $path, string $version, string $name, string $description): string + { + if ($description === '') { + $description = '// Add content'; + } else { + $description = "return '$description';"; + } + $file = new PhpFile(); + $class = $file->addClass(str_replace(' ', '', ucwords($name))); + $class + ->setFinal() + ->setExtends(\Migration::class) + ->addComment("Description of class.\nSecond line\n"); + $class->addMethod('description')->addBody($description); + $class->addMethod('up')->addBody('// Add content'); + $class->addMethod('down')->addBody('// Add content'); + + $printer = new StudipClassPrinter(); + $result = $printer->printFile($file); + $migrationName = $version . '_' . str_replace(' ', '_', lcfirst($name)); + $filename = $path . '/' . $migrationName . '.php'; + + file_put_contents($filename, $result); + + return $filename; + } +} diff --git a/cli/Commands/Make/Model.php b/cli/Commands/Make/Model.php new file mode 100644 index 0000000..57b15af --- /dev/null +++ b/cli/Commands/Make/Model.php @@ -0,0 +1,125 @@ +<?php + +namespace Studip\Cli\Commands\Make; + +use Nette\PhpGenerator\PhpFile; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; + + +final class Model extends Command +{ + protected static $defaultName = 'make:model'; + + protected function configure(): void + { + $this->setDescription('Create a sorm-model file'); + $this->addArgument('name', InputArgument::REQUIRED, 'The name of the sorm-model'); + $this->addArgument('db-table', InputArgument::OPTIONAL, 'The name of the related db-table'); + $this->addOption('namespace', 's', InputOption::VALUE_OPTIONAL, 'Namespace', ''); + $defaultPath = $GLOBALS['STUDIP_BASE_PATH'] . '/lib/models'; + $this->addOption( + 'path', + 'p', + InputOption::VALUE_OPTIONAL, + 'The location where the model file should be created', + $defaultPath + ); + } + + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $namespace = $input->getOption('namespace'); + $name = $input->getArgument('name'); + $dbTable = $input->getArgument('db-table'); + $path = $input->getOption('path'); + $verbose = $input->getOption('verbose'); + + $filename = $this->createModelFile( + $path, + $name, + $input, + $output, + $dbTable, + $namespace + ); + + if ($verbose) { + $output->writeln('Model file ' . $filename . ' created.'); + } + + return Command::SUCCESS; + } + + private function createModelFile( + string $path, + string $name, + InputInterface $input, + OutputInterface $output, + string $dbTable = null, + string $namespace = null, + ): string + { + if (!$dbTable) { + $dbTable = strtosnakecase($name); + } + + $file = new PhpFile(); + $className = str_replace(' ', '', ucwords($name)); + + if ($namespace) { + $className = ucfirst($namespace) . '\\' . $className; + } + $class = $file->addClass($className); + $class->setExtends(\SimpleORMap::class); + $class->addComment(ucfirst($name) . '.php'); + $class->addComment('model class for table ' . $dbTable); + $method = $class->addMethod('configure') + ->setStatic() + ->setProtected(); + + $method->addBody(sprintf('$config[\'db_table\'] = \'%s\';', $dbTable)); + $method->addBody('parent::configure($config);'); + $method->addParameter('config', []); + + + $printer = new StudipClassPrinter(); + $result = $printer->printFile($file); + + $modelName = str_replace(' ', '_', ucfirst($name)); + $filename = $path . '/' . $modelName . '.php'; + + file_put_contents($filename, $result); + + $helper = $this->getHelper('question'); + + $tableExists = \DBManager::get()->execute('SHOW TABLES LIKE ?', [$dbTable]); + + $describeModel = false; + if ($tableExists) { + $question = new ChoiceQuestion( + "\nDescribe model:\n", + $modelName + ); + $describeModel = $helper->ask($input, $output, $question); + } + + if ($describeModel) { + $greetInput = new ArrayInput([ + 'command' => 'sorm:describe', + 'name' => 'Fabien', + '--yell' => true, + ]); + + $returnCode = $this->getApplication()->doRun($greetInput, $output); + } + + return $filename; + } +} diff --git a/cli/Commands/Make/StudipClassPrinter.php b/cli/Commands/Make/StudipClassPrinter.php new file mode 100644 index 0000000..5e86085 --- /dev/null +++ b/cli/Commands/Make/StudipClassPrinter.php @@ -0,0 +1,18 @@ +<?php +namespace Studip\Cli\Commands\Make; + +use Nette\PhpGenerator\Printer; + +final class StudipClassPrinter extends Printer +{ + /** length of the line after which the line will break */ + public int $wrapLength = 120; + /** indentation character, can be replaced with a sequence of spaces */ + public string $indentation = ' '; + /** number of blank lines between properties */ + public int $linesBetweenProperties = 0; + /** number of blank lines between methods */ + public int $linesBetweenMethods = 1; + + public string $returnTypeColon = ': '; +} |
