diff --git a/src/Console/Command/ModuleCreateCommand.php b/src/Console/Command/ModuleCreateCommand.php index dd42e1d..036c1cf 100644 --- a/src/Console/Command/ModuleCreateCommand.php +++ b/src/Console/Command/ModuleCreateCommand.php @@ -15,6 +15,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\ConfirmationQuestion; /** * Module Command. @@ -34,9 +35,12 @@ class ModuleCreateCommand extends AbstractCommand const ROUTING_ENGINE_AURA = 'aura'; const ROUTING_ENGINE_LARAVEL = 'laravel'; const ROUTING_ENGINE_FASTROUTE = 'fastroute'; + const ROUTING_ENGINE_NULL = 'NullRouter'; protected $skeletonModuleDir; protected $modulesDir; + protected $moduleDir; + protected $moduleName; protected $tplEngine; protected $routingEngine; protected $configEnabledTemplatingEngines = []; @@ -49,10 +53,7 @@ class ModuleCreateCommand extends AbstractCommand 'src/Controller', 'tests', 'resources', - 'resources/routes', - 'resources/config', - 'resources/views', - 'resources/views/index', + 'resources/config' ]; /** @@ -63,6 +64,15 @@ class ModuleCreateCommand extends AbstractCommand 'resources/config/config.php', ]; + protected $tplEngineCoreFiles = [ + 'resources/views', + 'resources/views/index' + ]; + + protected $routingEngineCoreFiles = [ + 'resources/routes' + ]; + /** * @var array */ @@ -90,7 +100,7 @@ class ModuleCreateCommand extends AbstractCommand self::ROUTING_ENGINE_SYMFONY => [ 'src/Controller/Index.php', 'src/Controller/Shared.php', - 'resources/routes/symfony.yml', + 'resources/routes/symfony.yml' ], self::ROUTING_ENGINE_AURA => [ 'src/Controller/Index.php', @@ -110,11 +120,6 @@ class ModuleCreateCommand extends AbstractCommand ]; protected $routingEngineTokenMap = [ - self::ROUTING_ENGINE_SYMFONY => [ - '[ROUTING_LOAD_METHOD]' => 'loadSymfonyRoutes', - '[ROUTING_DEF_FILE]' => 'symfony.yml', - '[ROUTING_GETROUTES_RETVAL]' => '\Symfony\Component\Routing\RouteCollection', - ], self::ROUTING_ENGINE_AURA => [ '[ROUTING_LOAD_METHOD]' => 'loadAuraRoutes', '[ROUTING_DEF_FILE]' => 'aura.php', @@ -169,85 +174,50 @@ protected function configure() } /** - * @param InputInterface $input + * @param InputInterface $input * @param OutputInterface $output - * * @throws \Exception + * @return void */ protected function execute(InputInterface $input, OutputInterface $output) { - $moduleName = $input->getArgument('name'); - $moduleDir = $this->modulesDir . DIRECTORY_SEPARATOR . $moduleName; + $this->moduleName = $input->getArgument('name'); + $this->moduleDir = $this->modulesDir . DIRECTORY_SEPARATOR . $this->moduleName; // Acquire Module Information $this->askQuestions($input, $output); - $this->createModuleStructure($moduleDir, $moduleName); + $this->createModuleStructure($this->moduleDir, $this->moduleName); + $output->writeln("Created module successfully"); + $output->writeln("Name: {$this->moduleName}"); + $output->writeln(sprintf("Path: %s", $this->moduleDir)); + // Copy the core files - $this->copyFiles($this->skeletonModuleDir, $moduleDir, $this->coreFiles); + $this->copyFiles($this->skeletonModuleDir, $this->moduleDir, $this->coreFiles); - $tokenizedFiles = []; + $tokenizedFiles = $this->getTokenizedCoreFiles(); $tokens = []; - foreach ($this->coreFiles as $coreFile) { - $tokenizedFiles[] = $coreFile; - } - - if (!$this->isValidTemplatingEngine($this->tplEngine)) { - throw new \Exception('Invalid templating engine: ' . $this->tplEngine); - } - // TEMPLATING + $tokens['[MODULE_NAME]'] = $this->moduleName; - // Copy templating files over - $tplFiles = $this->tplEngineFilesMap[$this->tplEngine]; - $this->copyFiles($this->skeletonModuleDir, $moduleDir, $tplFiles); - - // Setting up templating tokens - foreach ($tplFiles as $tplFile) { - $tokenizedFiles[] = $tplFile; + if(null !== $this->tplEngine && $this->isValidTemplatingEngine($this->tplEngine)) { + $this->processTemplatingFiles(); + $output->writeln(sprintf("Templating: %s", $this->tplEngine)); } - $tokens['[MODULE_NAME]'] = $moduleName; - $tokens['[TPL_ENGINE_EXT]'] = $this->tplEngine; - - // ROUTING - if (!$this->isValidRoutingEngine($this->routingEngine)) { - throw new \Exception('Invalid routing engine: ' . $this->routingEngine); + if($this->isValidRoutingEngine($this->routingEngine)) { + $this->processRoutingFiles($tokenizedFiles, $tokens); + $output->writeln(sprintf("Router: %s", $this->routingEngine)); + } else { + $tokens['ROUTING_TRAIT'] = ''; } - // Copy routing files over - $routingFiles = $this->routingEngineFilesMap[$this->routingEngine]; - $this->copyFiles($this->skeletonModuleDir, $moduleDir, $routingFiles); - - // Setting up routing tokens - foreach ($routingFiles as $routingFile) { - $tokenizedFiles[] = $routingFile; - } - $routingTokensMap = $this->routingEngineTokenMap[$this->routingEngine]; - foreach ($routingTokensMap as $routingTokenKey => $routingTokenVal) { - $tokens[$routingTokenKey] = $routingTokenVal; - } - - // Replace tokens in all files - $this->replaceTokensInFiles($moduleDir, $tokenizedFiles, $tokens); - - if ($this->routingEngine === self::ROUTING_ENGINE_FASTROUTE) { - rename( - $moduleDir . DIRECTORY_SEPARATOR . $routingFiles[0], - str_replace('IndexInvoke', 'Index', $moduleDir . DIRECTORY_SEPARATOR . $routingFiles[0] - )); - } - - // Success - $output->writeln("Created module successfully"); - $output->writeln("Name: {$moduleName}"); - $output->writeln(sprintf("Routing: %s", $this->routingEngine)); - $output->writeln(sprintf("Templating: %s", $this->tplEngine)); - $output->writeln(sprintf("Path: %s", $moduleDir)); + // replace tokens from specified tokenizable files + $this->replaceTokensInFiles($this->moduleDir, $tokenizedFiles, $tokens); $output->writeln("This module is not enabled. Enable it in config[modules] key"); - $this->checkTemplatingEngines($input, $output); - $this->checkRouters($input, $output); + $this->checkEnabledTemplatingEngines($input, $output); + $this->checkEnabledRouters($input, $output); } protected function isValidTemplatingEngine($tplEngine) @@ -268,6 +238,7 @@ protected function isValidRoutingEngine($routingEngine) self::ROUTING_ENGINE_AURA, self::ROUTING_ENGINE_LARAVEL, self::ROUTING_ENGINE_FASTROUTE, + self::ROUTING_ENGINE_NULL, ]); } @@ -336,35 +307,21 @@ protected function createModuleStructure($moduleDir, $moduleName) */ protected function askQuestions(InputInterface $input, OutputInterface $output) { + $questionHelper = $this->getHelper('question'); + // Module DIR if ($input->getOption('dir') == null) { - $questionHelper = $this->getHelper('question'); $modulesDirQuestion = new ChoiceQuestion('Where is the modules dir?', [1 => $this->modulesDir], $this->modulesDir); $modulesDirQuestion->setErrorMessage('Modules dir: %s is invalid.'); $this->modulesDir = $questionHelper->ask($input, $output, $modulesDirQuestion); } - // Templating - if ($input->getOption('tpl') == null) { - $questionHelper = $this->getHelper('question'); - $tplQuestion = new ChoiceQuestion('Choose your templating engine [php]', [1 => 'php', 2 => 'twig', 3 => 'smarty', 4 => 'plates', 5 => 'latte'], 'php'); - $tplQuestion->setErrorMessage('Templating engine %s is invalid.'); - $this->tplEngine = $questionHelper->ask($input, $output, $tplQuestion); + if($this->askForTemplating($input, $output)) { + $this->chooseTemplatingEngine($input, $output); } - // Routing - if ($input->getOption('routing') == null) { - $questionHelper = $this->getHelper('question'); - $routingQuestion = new ChoiceQuestion('Choose your routing engine [symfony]', - [ - 1 => self::ROUTING_ENGINE_SYMFONY, - 2 => self::ROUTING_ENGINE_AURA, - 3 => self::ROUTING_ENGINE_LARAVEL, - 4 => self::ROUTING_ENGINE_FASTROUTE, - ], - 'symfony' - ); - $tplQuestion->setErrorMessage('Routing engine %s is invalid.'); - $this->routingEngine = $questionHelper->ask($input, $output, $routingQuestion); + + if($this->askForRouting($input, $output)) { + $this->chooseRouter($input, $output); } } @@ -372,7 +329,7 @@ protected function askQuestions(InputInterface $input, OutputInterface $output) * @param InputInterface $input * @param OutputInterface $output */ - private function checkRouters(InputInterface $input, OutputInterface $output) + private function checkEnabledRouters(InputInterface $input, OutputInterface $output) { // Aura Check if ($this->routingEngine == self::ROUTING_ENGINE_AURA && !class_exists('\Aura\Router\Router')) { @@ -393,7 +350,7 @@ private function checkRouters(InputInterface $input, OutputInterface $output) * @param InputInterface $input * @param OutputInterface $output */ - private function checkTemplatingEngines(InputInterface $input, OutputInterface $output) + private function checkEnabledTemplatingEngines(InputInterface $input, OutputInterface $output) { // PHP Templating Engine checks if ($this->tplEngine == self::TPL_ENGINE_PHP) { @@ -442,4 +399,179 @@ private function checkTemplatingEngines(InputInterface $input, OutputInterface $ } } } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return boolean + */ + private function askForTemplating(InputInterface $input, OutputInterface $output) + { + $questionHelper = $this->getHelper('question'); + $question = new ConfirmationQuestion("Do you need templates? (yes/no):\n", false); + + return $questionHelper->ask($input, $output, $question); + } + + private function askForRouting(InputInterface $input, OutputInterface $output) + { + $questionHelper = $this->getHelper('question'); + $question = new ConfirmationQuestion("Do you need routing? (yes/no):\n", false); + + return $questionHelper->ask($input, $output, $question); + } + + private function chooseTemplatingEngine($input, $output) + { + $tplQuestion = new ChoiceQuestion('Choose your templating engine [php]', + [ + 1 => 'php', + 2 => 'twig', + 3 => 'smarty', + 4 => 'plates', + 5 => 'latte', + 99 => 'skip' + ] + ); + $tplQuestion->setErrorMessage('Templating engine %s is invalid.'); + if(99 !== ($tplEngine = $this->getHelper('question')->ask($input, $output, $tplQuestion))) { + $this->tplEngine = $tplEngine; + } + } + + private function chooseRouter(InputInterface $input, OutputInterface $output) + { + $routingQuestion = new ChoiceQuestion('Choose your routing engine:', + [ + 1 => self::ROUTING_ENGINE_SYMFONY, + 2 => self::ROUTING_ENGINE_AURA, + 3 => self::ROUTING_ENGINE_LARAVEL, + 4 => self::ROUTING_ENGINE_FASTROUTE, + 99 => 'skip' + ] + ); + + // @todo - test question when you don't choose any option, or an invalid one (like -1) + $routingQuestion->setErrorMessage('Routing engine %s is invalid.'); + $chosenRouter = $this->getHelper('question')->ask($input, $output, $routingQuestion); + if(99 == $chosenRouter) { + $chosenRouter = 'NullRouter'; + } + $this->routingEngine = $chosenRouter; + } + + private function getTemplatingFilesFromEngine($tplEngine) + { + if(!isset($this->tplEngineFilesMap[$tplEngine])) { + throw new \InvalidArgumentException('Invalid templating engine specified for map files: ' . $tplEngine); + } + } + + private function processTemplatingFiles() + { + $tplFiles = $this->getTemplatingFilesFromEngine($this->tplEngine); + + // Copy core templating files over + foreach($this->tplEngineCoreFiles as $coreFile) { + $tplFiles[] = $coreFile; + } + + // Copy templating files over relevant to the specified engine + $this->copyFiles($this->skeletonModuleDir, $this->moduleDir, $tplFiles); + + // Setting up templating tokens + $tokenizedFiles = []; + foreach ($tplFiles as $tplFile) { + $tokenizedFiles[] = $tplFile; + } + + $tokens['[TPL_ENGINE_EXT]'] = $this->tplEngine; + + + $this->replaceTokensInFiles($this->moduleDir, $tokenizedFiles, $tokens); + + + } + + /** + * @throws \Exception + */ + private function processRoutingFiles($tokenizedFiles, $tokens) + { + + if(!isset($this->routingEngineFilesMap[$this->routingEngine])) { + throw new \Exception('Routing engine not found in routing files map: ' . $this->routingEngine); + } + + // Copy routing files over + $routingFiles = $this->routingEngineFilesMap[$this->routingEngine]; + + // If a valid routing engine and that's not null router + if($this->routingEngine !== 99) { + // Create core routing directories + foreach($this->routingEngineCoreFiles as $coreFile) { + @mkdir($this->moduleDir . DIRECTORY_SEPARATOR . $coreFile); + } + } + + +//var_dump(__METHOD__, __LINE__, $routingFiles); exit; + $this->copyFiles($this->skeletonModuleDir, $this->moduleDir, $routingFiles); + + // Setting up routing tokenizable files + foreach ($routingFiles as $routingFile) { + $tokenizedFiles[] = $routingFile; + } + + // Get all the tokens for this routing engine and the values the map to. + $routingTokensMap = $this->getRoutingTokenMap($this->routingEngine); + foreach ($routingTokensMap as $routingTokenKey => $routingTokenVal) { + $tokens[$routingTokenKey] = $routingTokenVal; + } + + // Replace tokens in all files + $this->replaceTokensInFiles($this->moduleDir, $tokenizedFiles, $tokens); + + // Replace the ROUTING placeholder with this heredoc + + // Prepare the fastroute route file + if ($this->routingEngine === self::ROUTING_ENGINE_FASTROUTE) { + rename( + $moduleDir . DIRECTORY_SEPARATOR . $routingFiles[0], + str_replace('IndexInvoke', 'Index', $moduleDir . DIRECTORY_SEPARATOR . $routingFiles[0] + )); + } + } + + protected function getTokenizedCoreFiles() + { + $files = []; + foreach ($this->coreFiles as $coreFile) { + $files[] = $coreFile; + } + return $files; + } + + private function getRoutingTokenMap($routingEngine) { + +// if(!isset($this->routingEngineTokenMap[$routingEngine])) { +// throw new \Exception('No routing engine tokenizable files found for routing engine: ' . $this->routingEngine); +// } + + $tokenMap = []; + + switch($routingEngine) { + case self::ROUTING_ENGINE_SYMFONY: + $tokenMap['[ROUTING_TRAIT]'] = 'use \PPI\Framework\Module\Routing\SymfonyTrait;'; + break; + + default: + throw new \Exception('Unimplemented routing engine: ' . $routingEngine); + break; + } + + return $tokenMap; + } + + } diff --git a/src/Module/AbstractModule.php b/src/Module/AbstractModule.php index b1aafa4..432a5c7 100644 --- a/src/Module/AbstractModule.php +++ b/src/Module/AbstractModule.php @@ -347,18 +347,6 @@ public function getConfig() return array(); } - /** - * Returns the default location of where Command classes are registered. - * Override this in your child module if it differs from this default convention. - * - * @return string - */ - public function getCommandsPath() - { - return sprintf("%s/src/Command", $this->getPath()); - } - - /** * Finds and registers Commands. * @@ -371,8 +359,7 @@ public function getCommandsPath() */ public function registerCommands(Application $application) { - - if (!is_dir($dir = $this->getCommandsPath())) { + if (!is_dir($dir = $this->getPath() . '/Command')) { return; } diff --git a/src/Module/Routing/SymfonyTrait.php b/src/Module/Routing/SymfonyTrait.php new file mode 100644 index 0000000..189739d --- /dev/null +++ b/src/Module/Routing/SymfonyTrait.php @@ -0,0 +1,23 @@ +loadSymfonyRoutes($this->getRoutingFilePath()); + } + + protected function getRoutingFilePath() + { + return $this->getPath() . '/resources/routes/symfony.yml'; + } + +} \ No newline at end of file