From 708600df958faac14856a406a850c27723083df9 Mon Sep 17 00:00:00 2001 From: FK Date: Wed, 28 Oct 2020 17:31:18 +0100 Subject: [PATCH 01/11] Core changes - replace Bootstrap property 'commands' with configuration - Add first event names in .phpstorm.meta - replace multiple Bootstrap instantiations by BootstrapManager get (avoid Multi-Instancing, eg for event attaching) --- Engine/Core/.meta/.phpstorm.meta.php | 14 +++++---- Engine/Core/Abstracts/AbstractBootstrap.php | 11 ------- Engine/Core/Helper/Helper.php | 2 +- Engine/Core/Manager/Modules/ModuleManager.php | 29 +++++++------------ Engine/Core/Services/PluginAccessService.php | 2 +- Engine/Core/Services/PluginStateService.php | 2 ++ 6 files changed, 23 insertions(+), 37 deletions(-) diff --git a/Engine/Core/.meta/.phpstorm.meta.php b/Engine/Core/.meta/.phpstorm.meta.php index 3946af5..2afa0c5 100644 --- a/Engine/Core/.meta/.phpstorm.meta.php +++ b/Engine/Core/.meta/.phpstorm.meta.php @@ -21,17 +21,19 @@ expectedArguments(\Oforge\Engine\TemplateEngine\Core\Twig\TwigFlash::addMessage(), 0, argumentsSet('oforge_flash_message_types')); expectedArguments(\Oforge\Engine\TemplateEngine\Core\Twig\TwigFlash::addExceptionMessage(), 0, argumentsSet('oforge_flash_message_types')); + // AbstractBootstrap configuration override(\Oforge\Engine\Core\Abstracts\AbstractBootstrap::getConfiguration(0), map([ - 'backendDashboardWidgets' => '', - 'backendNavigations' => '', 'settingGroups' => '', - 'twigExtensions' => '', ])); override(\Oforge\Engine\Core\Abstracts\AbstractBootstrap::setConfiguration(0), map([ - 'backendDashboardWidgets' => '', - 'backendNavigations' => '', 'settingGroups' => '', - 'twigExtensions' => '', + ])); + // Events + override(\Oforge\Engine\Core\Manager\Events\Event::create(0), map([ + 'Oforge:Extension:init' => '', + ])); + override(\Oforge\Engine\Core\Manager\Events\EventManager::attach(0), map([ + 'Oforge:Extension:init' => '', ])); } diff --git a/Engine/Core/Abstracts/AbstractBootstrap.php b/Engine/Core/Abstracts/AbstractBootstrap.php index cda8eb3..cdffe21 100644 --- a/Engine/Core/Abstracts/AbstractBootstrap.php +++ b/Engine/Core/Abstracts/AbstractBootstrap.php @@ -12,10 +12,6 @@ * @package Oforge\Engine\Core\Abstracts */ abstract class AbstractBootstrap { - /** - * @var string[] $commands - */ - protected $commands = []; /** * @var string[] $cronjobs */ @@ -74,13 +70,6 @@ public function deactivate() { public function load() { } - /** - * @return string[] - */ - public function getCommands() { - return $this->commands; - } - /** * @return string[] */ diff --git a/Engine/Core/Helper/Helper.php b/Engine/Core/Helper/Helper.php index 72ada52..64df9b9 100644 --- a/Engine/Core/Helper/Helper.php +++ b/Engine/Core/Helper/Helper.php @@ -72,7 +72,7 @@ public static function getBootstrapInstance($pluginName) : AbstractBootstrap { $className = $pluginName . "\\Bootstrap"; if (is_subclass_of($className, AbstractBootstrap::class)) { - return new $className(); + return Oforge()->getBootstrapManager()->getBootstrapInstance($className); } throw new InvalidClassException($className, AbstractBootstrap::class); } diff --git a/Engine/Core/Manager/Modules/ModuleManager.php b/Engine/Core/Manager/Modules/ModuleManager.php index 6705032..13418e5 100644 --- a/Engine/Core/Manager/Modules/ModuleManager.php +++ b/Engine/Core/Manager/Modules/ModuleManager.php @@ -15,6 +15,7 @@ use Oforge\Engine\Core\Forge\ForgeEntityManager; use Oforge\Engine\Core\Helper\Helper; use Oforge\Engine\Core\Helper\Statics; +use Oforge\Engine\Core\Manager\Events\Event; use Oforge\Engine\Core\Models\Module\Module; use Oforge\Engine\Core\Services\MiddlewareService; @@ -86,11 +87,9 @@ public function init() $bucket = []; // add all modules except of the core bootstrap file foreach ($modules as $module) { - /** - * @var $module Module - */ + /** @var Module $module */ $classname = $module->getName(); - $instance = new $classname(); + $instance = Oforge()->getBootstrapManager()->getBootstrapInstance($classname); if (get_class($instance) != Bootstrap::class) { array_push($bucket, $instance); } @@ -159,10 +158,8 @@ public function init() protected function register($className) { if (is_subclass_of($className, AbstractBootstrap::class)) { - /** - * @var $instance AbstractBootstrap - */ - $instance = new $className(); + /** @var AbstractBootstrap $instance */ + $instance = Oforge()->getBootstrapManager()->getBootstrapInstance($className); $moduleEntry = $this->moduleRepository()->findBy(["name" => get_class($instance)]); if (isset($moduleEntry) && sizeof($moduleEntry) > 0) { @@ -188,11 +185,9 @@ protected function register($className) protected function initModule($className) { if (is_subclass_of($className, AbstractBootstrap::class)) { - /** - * @var $instance AbstractBootstrap - */ - $instance = new $className(); - + /** @var AbstractBootstrap $instance */ + $instance = Oforge()->getBootstrapManager()->getBootstrapInstance($className); + Oforge()->Events()->trigger(Event::create('Oforge:Extension:init', ['bootstrap' => $instance])); Oforge()->DB()->initModelSchema($instance->getModels()); $services = $instance->getServices(); @@ -243,11 +238,9 @@ private function initCoreModule($className) $startTime = microtime(true) * 1000; if (is_subclass_of($className, AbstractBootstrap::class)) { - /** - * @var $instance AbstractBootstrap - */ - $instance = new $className(); - + /** @var AbstractBootstrap $instance */ + $instance = Oforge()->getBootstrapManager()->getBootstrapInstance($className); + Oforge()->Events()->trigger(Event::create('Oforge:Extension:init', ['bootstrap' => $instance])); Oforge()->DB()->initModelSchema($instance->getModels()); $services = $instance->getServices(); diff --git a/Engine/Core/Services/PluginAccessService.php b/Engine/Core/Services/PluginAccessService.php index 48ee9b6..54b2f9c 100644 --- a/Engine/Core/Services/PluginAccessService.php +++ b/Engine/Core/Services/PluginAccessService.php @@ -29,7 +29,7 @@ public function getActive() { foreach ($plugins as $plugin) { $classname = $plugin->getName() . "\\Bootstrap"; - $instance = new $classname(); + $instance = Oforge()->getBootstrapManager()->getBootstrapInstance($classname); $dependencies = array_map(function ($val) { return explode('\\', $val)[0]; }, $instance->getDependencies()); diff --git a/Engine/Core/Services/PluginStateService.php b/Engine/Core/Services/PluginStateService.php index eb8ebc2..276cdc4 100644 --- a/Engine/Core/Services/PluginStateService.php +++ b/Engine/Core/Services/PluginStateService.php @@ -21,6 +21,7 @@ use Oforge\Engine\Core\Exceptions\ServiceNotFoundException; use Oforge\Engine\Core\Exceptions\Template\TemplateNotFoundException; use Oforge\Engine\Core\Helper\Helper; +use Oforge\Engine\Core\Manager\Events\Event; use Oforge\Engine\Core\Models\Plugin\Plugin; use Oforge\Engine\TemplateEngine\Core\Exceptions\InvalidScssVariableException; use Oforge\Engine\TemplateEngine\Core\Services\TemplateManagementService; @@ -58,6 +59,7 @@ public function initPlugin($pluginName) { if (isset($plugin) && $plugin->getActive()) { $instance = Helper::getBootstrapInstance($pluginName); if (isset($instance)) { + Oforge()->Events()->trigger(Event::create('Oforge:Extension:init', ['bootstrap' => $instance])); Oforge()->DB()->initModelSchema($instance->getModels()); $services = $instance->getServices(); Oforge()->Services()->register($services); From 337e093e26b7fe8d4f5beaaae5764ad63a8706c0 Mon Sep 17 00:00:00 2001 From: FK Date: Wed, 28 Oct 2020 17:33:36 +0100 Subject: [PATCH 02/11] Replace old custom console extension with extension based on symfony console, separate doctrine commands to doctrine-bin --- Engine/Console/.meta/.phpstorm.meta.php | 8 +- .../Abstracts/AbstractBatchCallCommand.php | 97 +++++ .../Abstracts/AbstractBatchCommand.php | 67 ---- Engine/Console/Abstracts/AbstractCommand.php | 146 +++++--- .../Abstracts/AbstractGroupCommand.php | 65 ---- .../AbstractNamespaceCallCommand.php | 81 +++++ Engine/Console/Bootstrap.php | 51 +-- .../Cleanup/CleanupLogfilesCommand.php | 42 --- .../Commands/Console/CommandListCommand.php | 72 ---- Engine/Console/Commands/Core/PingCommand.php | 36 +- .../Core/ProcessAsyncEventsCommand.php | 31 +- .../Commands/Dev/DevCleanupBatchCommand.php | 26 -- .../Dev/DevDoctrineOrmCacheCleanupCommand.php | 38 -- .../Doctrine/DoctrineOrmWrapperCommand.php | 39 -- .../Example/ExampleBatchCallCommand.php | 18 + .../Commands/Example/ExampleBatchCommand.php | 25 -- .../Commands/Example/ExampleCommand1.php | 28 ++ .../Commands/Example/ExampleCommand2.php | 28 ++ .../Commands/Example/ExampleCommand3.php | 28 ++ .../Commands/Example/ExampleCommandOne.php | 31 -- .../Commands/Example/ExampleCommandThree.php | 31 -- .../Commands/Example/ExampleCommandTwo.php | 31 -- .../Commands/Example/ExampleGroupCommand.php | 25 -- .../Example/ExampleNamespaceCallCommand.php | 18 + .../Commands/Service/ServiceListCommand.php | 85 ----- .../Commands/Service/ServiceRunCommand.php | 113 ------ Engine/Console/ConsoleStatics.php | 28 -- Engine/Console/Lib/ConsoleRenderer.php | 344 ------------------ Engine/Console/Lib/Input.php | 108 ------ .../Monolog/Formatter/ConsoleFormatter.php | 33 -- Engine/Console/Managers/ConsoleManager.php | 113 ++++++ Engine/Console/Services/ConsoleService.php | 319 ---------------- bin/console | 14 +- bin/doctrine | 2 + bin/php/_include.php | 4 + bin/php/console.php | 7 + bin/php/doctrine.php | 17 + composer.json | 1 - 38 files changed, 588 insertions(+), 1662 deletions(-) create mode 100644 Engine/Console/Abstracts/AbstractBatchCallCommand.php delete mode 100644 Engine/Console/Abstracts/AbstractBatchCommand.php delete mode 100644 Engine/Console/Abstracts/AbstractGroupCommand.php create mode 100644 Engine/Console/Abstracts/AbstractNamespaceCallCommand.php delete mode 100644 Engine/Console/Commands/Cleanup/CleanupLogfilesCommand.php delete mode 100644 Engine/Console/Commands/Console/CommandListCommand.php delete mode 100644 Engine/Console/Commands/Dev/DevCleanupBatchCommand.php delete mode 100644 Engine/Console/Commands/Dev/DevDoctrineOrmCacheCleanupCommand.php delete mode 100644 Engine/Console/Commands/Doctrine/DoctrineOrmWrapperCommand.php create mode 100644 Engine/Console/Commands/Example/ExampleBatchCallCommand.php delete mode 100644 Engine/Console/Commands/Example/ExampleBatchCommand.php create mode 100644 Engine/Console/Commands/Example/ExampleCommand1.php create mode 100644 Engine/Console/Commands/Example/ExampleCommand2.php create mode 100644 Engine/Console/Commands/Example/ExampleCommand3.php delete mode 100644 Engine/Console/Commands/Example/ExampleCommandOne.php delete mode 100644 Engine/Console/Commands/Example/ExampleCommandThree.php delete mode 100644 Engine/Console/Commands/Example/ExampleCommandTwo.php delete mode 100644 Engine/Console/Commands/Example/ExampleGroupCommand.php create mode 100644 Engine/Console/Commands/Example/ExampleNamespaceCallCommand.php delete mode 100644 Engine/Console/Commands/Service/ServiceListCommand.php delete mode 100644 Engine/Console/Commands/Service/ServiceRunCommand.php delete mode 100644 Engine/Console/ConsoleStatics.php delete mode 100644 Engine/Console/Lib/ConsoleRenderer.php delete mode 100644 Engine/Console/Lib/Input.php delete mode 100644 Engine/Console/Lib/Monolog/Formatter/ConsoleFormatter.php create mode 100644 Engine/Console/Managers/ConsoleManager.php delete mode 100644 Engine/Console/Services/ConsoleService.php create mode 100644 bin/doctrine create mode 100644 bin/php/_include.php create mode 100644 bin/php/console.php create mode 100644 bin/php/doctrine.php diff --git a/Engine/Console/.meta/.phpstorm.meta.php b/Engine/Console/.meta/.phpstorm.meta.php index 51e397a..70b365b 100644 --- a/Engine/Console/.meta/.phpstorm.meta.php +++ b/Engine/Console/.meta/.phpstorm.meta.php @@ -3,8 +3,12 @@ namespace PHPSTORM_META { if (function_exists('override')) { - override(\Oforge\Engine\Core\Manager\Services\ServiceManager::get(0), map([ - 'console' => \Oforge\Engine\Console\Services\ConsoleService::class, + // AbstractBootstrap configuration + override(\Oforge\Engine\Core\Abstracts\AbstractBootstrap::getConfiguration(0), map([ + 'commands' => '', + ])); + override(\Oforge\Engine\Core\Abstracts\AbstractBootstrap::setConfiguration(0), map([ + 'commands' => '', ])); } diff --git a/Engine/Console/Abstracts/AbstractBatchCallCommand.php b/Engine/Console/Abstracts/AbstractBatchCallCommand.php new file mode 100644 index 0000000..e58cd52 --- /dev/null +++ b/Engine/Console/Abstracts/AbstractBatchCallCommand.php @@ -0,0 +1,97 @@ + '', // Command name with method name(for dynamic inout at runtime), must be in static class. + * 'command_1' => 'arg_1 --option_1', // Command name with string input + * 'command_1' => [ // Command name with array input + * // 'command' => 'command_1', // Command key, optional. If not present, key is prepended. + * 'arg_1' => value, + * '--option_1' => value, + * ], + * ] + * + * @var array $commands + */ + protected $commands = null; + + /** + * AbstractBatchCallCommand constructor. + * + * @param string|null $name + * @param array $commands + */ + public function __construct(string $name = null, array $commands = []) { + $this->commands = $this->commands ?? $commands; + $this->checkBatchCallConfig(); + parent::__construct($name); + } + + /** @inheritdoc */ + protected function configure() { + $this->addOption(self::OPTION_STOP_ON_ERROR, null, InputOption::VALUE_NONE, 'Quit when a subcommand fails.'); + parent::configure(); + } + + /** + * @inheritDoc + * @throws Exception + */ + protected function execute(InputInterface $input, OutputInterface $output) : int { + $this->checkBatchCallConfig(); + $stopOnError = $this->getDefinition()->hasOption(self::OPTION_STOP_ON_ERROR) && $input->hasOption(self::OPTION_STOP_ON_ERROR); + foreach ($this->commands as $name => $args) { + if (!is_string($name)) { + $name = $args; + $args = []; + } + if ($this->getName() === $name) { + continue; + } + $errorCode = $this->callOtherCommand($output, $name, $args); + if ($errorCode === self::FAILURE && $stopOnError) { + return self::FAILURE; + } + } + + return self::SUCCESS; + } + + private function checkBatchCallConfig() { + if (!isset($this->commands)) { + //TODO + } + if (empty($this->commands)) { + //TODO + } + foreach ($this->commands as $name => $args) { + if (!is_string($name)) { + $name = $args; + $args = []; + } + if (!is_string($name)) { + //TODO + } + if (!(is_string($args) || is_array($args))) { + //TODO + } + } + } + +} diff --git a/Engine/Console/Abstracts/AbstractBatchCommand.php b/Engine/Console/Abstracts/AbstractBatchCommand.php deleted file mode 100644 index 9d8a52b..0000000 --- a/Engine/Console/Abstracts/AbstractBatchCommand.php +++ /dev/null @@ -1,67 +0,0 @@ -excludeCommands = $excludeCommands; - try { - $this->consoleService = Oforge()->Services()->get('console'); - } catch (ServiceNotFoundException $exception) { - Oforge()->Logger()->get()->error($exception->getMessage(), $exception->getTrace()); - throw $exception; - } - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - $prefix = $this->getName() . AbstractCommand::SUBCOMMAND_SEPARATOR; - $exclude = array_flip($this->excludeCommands); - $commandNames = []; - $commands = $this->consoleService->getCommands(self::ALL_TYPES); - foreach ($commands as $command) { - if (StringHelper::startsWith($command->getName(), $prefix) && !isset($exclude[$command->getName()])) { - $commandNames[] = $command->getName(); - } - } - sort($commandNames); - foreach ($commandNames as $command) { - $output->notice('Run batch sub command: ' . $command); - $this->consoleService->runCommand($command, ''); - } - } - -} diff --git a/Engine/Console/Abstracts/AbstractCommand.php b/Engine/Console/Abstracts/AbstractCommand.php index 15cca18..8b67697 100644 --- a/Engine/Console/Abstracts/AbstractCommand.php +++ b/Engine/Console/Abstracts/AbstractCommand.php @@ -2,72 +2,118 @@ namespace Oforge\Engine\Console\Abstracts; -use GetOpt\Command; -use Monolog\Logger; -use Oforge\Engine\Console\Lib\Input; +use Exception; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\OutputInterface; /** - * Class AbstractCommand + * Class AbstractCallCommand * * @package Oforge\Engine\Console\Abstracts */ abstract class AbstractCommand extends Command { - public const ALL_TYPES = 0; - public const TYPE_DEFAULT = 1; - public const TYPE_EXTENDED = 2; - public const TYPE_DEVELOPMENT = 4; - public const TYPE_CRONJOB = 8; - public const TYPE_HIDDEN = 16; /** - * Separator for subcommands. - */ - public const SUBCOMMAND_SEPARATOR = ':'; - /** - * @var int $type Type of command. - */ - private $type; - - /** - * AbstractCommand constructor. + * Configuration: + * $config = [ + * 'name' => string, // Optional, alternative use $defaultName. + * 'description' => string, // Optional but recommended + * 'aliases' => string | string[], // optional + * 'hidden' => bool, // Optional, default=false + * 'processTitle' => string, // Optional + * 'usage' => string | string[], // optional + * 'help' => string, // optional + * 'arguments' => [ // Optional + * '' => [ + * 'mode' => InputArgument:: *, // Optional, default InputArgument::OPTIONAL, + * 'description' => string, // Optional but recommended + * 'default' => mixed, // Optional + * ], // * + * ], + * 'options' => [ // Optional + * '' => [ // Long option name ('--'). + * 'shortcut' => string | string[], // Optional. The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * 'mode' => InputOption::VALUE_ *, // Optional, default InputOption::VALUE_NONE, + * 'description' => string, // Optional but recommended + * 'default' => mixed, // Optional. If mode=InputOption::VALUE_NONE, default will be ignored. + * ], // * + * ], + * ]; * - * @param string $name Name of command - * @param int $type [Default: AbstractCommand::TYPE_DEFAULT] + * @var array $config */ - public function __construct(string $name, int $type = self::TYPE_DEFAULT) { - parent::__construct($name, [$this, 'handle']); - $this->type = in_array($type, [ - self::TYPE_HIDDEN, - self::TYPE_CRONJOB, - self::TYPE_DEVELOPMENT, - self::TYPE_EXTENDED, - self::TYPE_DEFAULT, - ]) ? $type : self::TYPE_DEFAULT; - } + protected $config = []; - /** - * @return int - */ - public function getType() : int { - return $this->type; + /** @inheritdoc */ + protected function configure() { + if (isset($this->config) && !empty($this->config)) { + $config = $this->config; + $mapping = [ + 'name' => 'setName', + 'description' => 'setDescription', + 'aliases' => 'setAliases', + 'hidden' => 'setHidden', + 'processTitle' => 'setProcessTitle', + 'usage' => 'setProcessTitle', + 'help' => 'setHelp', + ]; + foreach ($mapping as $key => $method) { + if (isset($config[$key])) { + $this->$method($config[$key]); + } + } + if (isset($config['usage'])) { + $usage = $config['usage']; + if (!is_array($usage)) { + $usage = [$usage]; + } + foreach ($usage as $u) { + $this->addUsage($u); + } + } + if (isset($config['arguments']) && is_array($config['arguments'])) { + foreach ($config['arguments'] as $argumentName => $argumentConfig) { + $mode = $argumentConfig['mode'] ?? InputArgument::OPTIONAL; + $description = $argumentConfig['description'] ?? ''; + $default = $argumentConfig['default'] ?? null; + $this->addArgument($argumentName, $mode, $description, $default); + } + } + if (isset($config['options']) && is_array($config['options'])) { + foreach ($config['options'] as $optionName => $optionConfig) { + $shortcut = $argumentConfig['shortcut'] ?? null; + $mode = $argumentConfig['mode'] ?? InputOption::VALUE_NONE; + $description = $argumentConfig['description'] ?? ''; + $default = $argumentConfig['default'] ?? null; + if ($mode === InputOption::VALUE_NONE) { + $default = null; + } + $this->addOption($optionName, $shortcut, $mode, $description, $default); + } + } + } } /** - * @param int $type + * @param OutputInterface $output + * @param string $name + * @param string|array $args * - * @return AbstractCommand + * @return int + * @throws Exception */ - protected function setType(int $type) : AbstractCommand { - $this->type = $type; + protected function callOtherCommand(OutputInterface $output, string $name, $args) { + $command = $this->getApplication()->find($name); + if (is_string($args)) { + $args = new StringInput($args); + } elseif (is_array($args)) { + $args = new ArrayInput($args); + } - return $this; + return $command->run($args, $output); } - /** - * Command handle function. - * - * @param Input $input - * @param Logger $output - */ - abstract public function handle(Input $input, Logger $output) : void; - } diff --git a/Engine/Console/Abstracts/AbstractGroupCommand.php b/Engine/Console/Abstracts/AbstractGroupCommand.php deleted file mode 100644 index 0074d03..0000000 --- a/Engine/Console/Abstracts/AbstractGroupCommand.php +++ /dev/null @@ -1,65 +0,0 @@ - commandArgs pairs. - * @param int $type [Default: AbstractCommand::TYPE_DEFAULT] - * - * @throws ServiceNotFoundException - */ - public function __construct(string $name, array $croupCommands, int $type = self::TYPE_DEFAULT) { - parent::__construct($name, $type); - $this->groupCommands = $croupCommands; - try { - $this->consoleService = Oforge()->Services()->get('console'); - } catch (ServiceNotFoundException $exception) { - Oforge()->Logger()->get()->error($exception->getMessage(), $exception->getTrace()); - throw $exception; - } - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - $commands = $this->groupCommands; - foreach ($commands as $command => $commandArgs) { - if (!is_string($command)) { - $command = $commandArgs; - $commandArgs = ''; - } - if ($this->getName() === $command) { - continue; - } - $commandArgs = is_string($commandArgs) && !empty($commandArgs) ? $commandArgs : ''; - $output->notice('Run group sub command: ' . $command . ' ' . $commandArgs); - $this->consoleService->runCommand($command, $commandArgs); - } - } - -} diff --git a/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php b/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php new file mode 100644 index 0000000..e222c4a --- /dev/null +++ b/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php @@ -0,0 +1,81 @@ +namespace = rtrim($this->namespace ?? trim($namespace), ':'); + $this->excludeCommands = $this->excludeCommands ?? (empty($excludeCommands) ? null : $excludeCommands); + $this->checNamespaceCallConfig(); + parent::__construct(static::$defaultName ?? $this->namespace); + } + + /** @inheritdoc */ + protected function configure() { + $this->addOption(self::OPTION_STOP_ON_ERROR, null, InputOption::VALUE_NONE, 'Quit when a subcommand fails.'); + $this->setDescription('Call all commands of namespace: ' . $this->namespace); + parent::configure(); + } + + /** + * @inheritDoc + * @throws Exception + */ + protected function execute(InputInterface $input, OutputInterface $output) : int { + $this->checNamespaceCallConfig(); + $stopOnError = $this->getDefinition()->hasOption(self::OPTION_STOP_ON_ERROR) && $input->hasOption(self::OPTION_STOP_ON_ERROR); + $commands = $this->getApplication()->all($this->namespace); + if (!is_array($commands)) { + $commands = [$commands]; + } + $exclude = array_flip($this->excludeCommands); + foreach ($commands as $command) { + if ($command->getName() === $this->getName() || isset($exclude[$command->getName()])) { + continue; + } + $errorCode = $this->callOtherCommand($output, $command->getName(), []); + if ($errorCode === self::FAILURE && $stopOnError) { + return self::FAILURE; + } + } + + return self::SUCCESS; + } + + private function checNamespaceCallConfig() { + if (empty($this->namespace)) { + //TODO + } + } +} diff --git a/Engine/Console/Bootstrap.php b/Engine/Console/Bootstrap.php index ec4f8a1..f86e59d 100644 --- a/Engine/Console/Bootstrap.php +++ b/Engine/Console/Bootstrap.php @@ -2,22 +2,9 @@ namespace Oforge\Engine\Console; -use Oforge\Engine\Console\Commands\Cleanup\CleanupLogfilesCommand; -use Oforge\Engine\Console\Commands\Console\CommandListCommand; -use Oforge\Engine\Console\Commands\Core\PingCommand; -use Oforge\Engine\Console\Commands\Core\ProcessAsyncEventsCommand; -use Oforge\Engine\Console\Commands\Dev\DevCleanupBatchCommand; -use Oforge\Engine\Console\Commands\Dev\DevDoctrineOrmCacheCleanupCommand; -use Oforge\Engine\Console\Commands\Doctrine\DoctrineOrmWrapperCommand; -use Oforge\Engine\Console\Commands\Example\ExampleBatchCommand; -use Oforge\Engine\Console\Commands\Example\ExampleCommandOne; -use Oforge\Engine\Console\Commands\Example\ExampleCommandThree; -use Oforge\Engine\Console\Commands\Example\ExampleCommandTwo; -use Oforge\Engine\Console\Commands\Example\ExampleGroupCommand; -use Oforge\Engine\Console\Commands\Service\ServiceListCommand; -use Oforge\Engine\Console\Commands\Service\ServiceRunCommand; -use Oforge\Engine\Console\Services\ConsoleService; +use Oforge\Engine\Console\Managers\ConsoleManager; use Oforge\Engine\Core\Abstracts\AbstractBootstrap; +use Oforge\Engine\Core\Manager\Events\Event; /** * Class Console-Bootstrap @@ -30,25 +17,21 @@ class Bootstrap extends AbstractBootstrap { * Console-Bootstrap constructor. */ public function __construct() { - $this->commands = [ - CleanupLogfilesCommand::class, - DevCleanupBatchCommand::class, - DevDoctrineOrmCacheCleanupCommand::class, - CommandListCommand::class, - DoctrineOrmWrapperCommand::class, - ExampleBatchCommand::class, - ExampleGroupCommand::class, - ExampleCommandOne::class, - ExampleCommandTwo::class, - ExampleCommandThree::class, - PingCommand::class, - ProcessAsyncEventsCommand::class, - ServiceListCommand::class, - ServiceRunCommand::class, - ]; - $this->services = [ - 'console' => ConsoleService::class, - ]; + $this->setConfiguration('commands', [ + Commands\Core\PingCommand::class, + Commands\Core\ProcessAsyncEventsCommand::class, + Commands\Example\ExampleBatchCallCommand::class, + Commands\Example\ExampleCommand1::class, + Commands\Example\ExampleCommand2::class, + Commands\Example\ExampleCommand3::class, + Commands\Example\ExampleNamespaceCallCommand::class, + ]); + + Oforge()->Events()->attach('Oforge:Extension:init', Event::SYNC, function(Event $event) { + /** @var AbstractBootstrap $boostrap */ + $boostrap = $event->getDataValue('bootstrap'); + ConsoleManager::registerCommandClasses($boostrap->getConfiguration('commands')); + }); } } diff --git a/Engine/Console/Commands/Cleanup/CleanupLogfilesCommand.php b/Engine/Console/Commands/Cleanup/CleanupLogfilesCommand.php deleted file mode 100644 index da8d550..0000000 --- a/Engine/Console/Commands/Cleanup/CleanupLogfilesCommand.php +++ /dev/null @@ -1,42 +0,0 @@ -setDescription('Cleanup log files.'); - $this->addOptions([ - Option::create('d', 'days', GetOpt::OPTIONAL_ARGUMENT)# - ->setDescription('Remove files older x days')# - ->setValidation('is_numeric')->setDefaultValue(false),# - ]); - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - if ($input->getOption('days')) { - Oforge()->Logger()->cleanupLogfiles((int) $input->getOption('days')); - } else { - Oforge()->Logger()->cleanupLogfiles(); - } - } - -} diff --git a/Engine/Console/Commands/Console/CommandListCommand.php b/Engine/Console/Commands/Console/CommandListCommand.php deleted file mode 100644 index 3067b10..0000000 --- a/Engine/Console/Commands/Console/CommandListCommand.php +++ /dev/null @@ -1,72 +0,0 @@ -setDescription('Display command list'); - $this->addOperands([ - Operand::create('filter', Operand::OPTIONAL)# - ->setDescription('Optional command prefix for filtering')# - ->setDefaultValue(''),# - ]); - $this->addOptions([ - Option::create('e', 'extended')# - ->setDescription('Include extended commands')# - ->setDefaultValue(0),# - Option::create(null, 'cronjob')# - ->setDescription('Display only cronjob commands')# - ->setDefaultValue(0),# - Option::create(null, 'dev')# - ->setDescription('Display only development commands')# - ->setDefaultValue(0),# - ]); - } - - /** - * @inheritdoc - * @throws ServiceNotFoundException - */ - public function handle(Input $input, Logger $output) : void { - $listType = self::TYPE_DEFAULT; - if ($input->getOption('cronjob')) { - $listType = self::TYPE_CRONJOB; - } elseif ($input->getOption('dev')) { - $listType = self::TYPE_DEVELOPMENT; - } elseif ($input->getOption('extended')) { - $listType |= self::TYPE_EXTENDED; - } - $prefix = $input->getOperand('filter'); - $prefixLength = strlen($prefix); - /** @var ConsoleService $consoleService */ - $consoleService = Oforge()->Services()->get('console'); - $commands = $consoleService->getCommands($listType); - if ($prefixLength > 0) { - $commands = array_filter($commands, function ($command) use ($prefix, $prefixLength) { - /** @var Command $command */ - return substr($command->getName(), 0, $prefixLength) === $prefix; - }); - } - echo $consoleService->getRenderer()->renderCommands($commands, false); - } - -} diff --git a/Engine/Console/Commands/Core/PingCommand.php b/Engine/Console/Commands/Core/PingCommand.php index 36c77ff..2a9b4a6 100644 --- a/Engine/Console/Commands/Core/PingCommand.php +++ b/Engine/Console/Commands/Core/PingCommand.php @@ -2,11 +2,10 @@ namespace Oforge\Engine\Console\Commands\Core; -use Monolog\Logger; use Oforge\Engine\Console\Abstracts\AbstractCommand; -use Oforge\Engine\Console\Lib\Input; -use Oforge\Engine\Core\Exceptions\ServiceNotFoundException; use Oforge\Engine\Core\Services\PingService; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; /** * Class PingCommand @@ -14,28 +13,19 @@ * @package Oforge\Engine\Console\Commands\Core */ class PingCommand extends AbstractCommand { + /** @var string[] $config */ + protected $config = [ + 'name' => 'oforge:ping', + 'description' => 'Ping function to test system.', + ]; - /** - * PingCommand constructor. - */ - public function __construct() { - parent::__construct('ping', self::TYPE_DEFAULT); - $this->setDescription('Ping Oforge'); - } + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + /** @var PingService $pingService */ + $pingService = Oforge()->Services()->get('ping'); + $output->writeln($pingService->me()); - /** - * @inheritdoc - * @throws ServiceNotFoundException - */ - public function handle(Input $input, Logger $output) : void { - try { - /** @var PingService $pingService */ - $pingService = Oforge()->Services()->get('ping'); - $output->notice($pingService->me()); - } catch (ServiceNotFoundException $exception) { - Oforge()->Logger()->get()->error($exception->getMessage(), $exception->getTrace()); - throw $exception; - } + return self::SUCCESS; } } diff --git a/Engine/Console/Commands/Core/ProcessAsyncEventsCommand.php b/Engine/Console/Commands/Core/ProcessAsyncEventsCommand.php index fc9cd52..07b5834 100644 --- a/Engine/Console/Commands/Core/ProcessAsyncEventsCommand.php +++ b/Engine/Console/Commands/Core/ProcessAsyncEventsCommand.php @@ -2,9 +2,9 @@ namespace Oforge\Engine\Console\Commands\Core; -use Monolog\Logger; use Oforge\Engine\Console\Abstracts\AbstractCommand; -use Oforge\Engine\Console\Lib\Input; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; /** * Class ProcessAsyncEventsCommand @@ -12,22 +12,19 @@ * @package Oforge\Engine\Console\Commands\Core */ class ProcessAsyncEventsCommand extends AbstractCommand { + /** @var array $config */ + protected $config = [ + 'name' => 'oforge:events:process-async', + 'description' => 'Async events processing', + 'hidden' => true, + ]; - /** - * PingCommand constructor. - */ - public function __construct() { - parent::__construct('oforge:events:process-async', self::TYPE_DEFAULT); - $this->setDescription('Async events processing'); - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - $output->info('Start async event processing'); + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + $output->writeln('Start async event processing'); Oforge()->Events()->processAsyncEvents(); - $output->info('Finished'); - } + $output->writeln('Finished'); + return self::SUCCESS; + } } diff --git a/Engine/Console/Commands/Dev/DevCleanupBatchCommand.php b/Engine/Console/Commands/Dev/DevCleanupBatchCommand.php deleted file mode 100644 index fb157d4..0000000 --- a/Engine/Console/Commands/Dev/DevCleanupBatchCommand.php +++ /dev/null @@ -1,26 +0,0 @@ -setDescription('Run all oforge:dev:cleanup:* cleanup commands.'); - } - -} diff --git a/Engine/Console/Commands/Dev/DevDoctrineOrmCacheCleanupCommand.php b/Engine/Console/Commands/Dev/DevDoctrineOrmCacheCleanupCommand.php deleted file mode 100644 index d55277a..0000000 --- a/Engine/Console/Commands/Dev/DevDoctrineOrmCacheCleanupCommand.php +++ /dev/null @@ -1,38 +0,0 @@ -setDescription('Remove doctrine orm cache folder'); - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - $directory = ROOT_PATH . Statics::DIR_CACHE; - if (FileSystemHelper::remove($directory, true)) { - $output->notice('Doctrine orm cache directory cleared.'); - } else { - $output->notice('Doctrine orm cache directory could not be cleared.'); - } - } - -} diff --git a/Engine/Console/Commands/Doctrine/DoctrineOrmWrapperCommand.php b/Engine/Console/Commands/Doctrine/DoctrineOrmWrapperCommand.php deleted file mode 100644 index 01be3fd..0000000 --- a/Engine/Console/Commands/Doctrine/DoctrineOrmWrapperCommand.php +++ /dev/null @@ -1,39 +0,0 @@ -setDescription('Run doctrine orm command or show list of commands'); - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - $entityManager = Oforge()->DB()->getForgeEntityManager()->getEntityManager(); - $helperSet = ConsoleRunner::createHelperSet($entityManager); - $helperSet->set(new EntityManagerHelper($entityManager), 'em'); - $helperSet->set(new ConnectionHelper($entityManager->getConnection()), 'db'); - $_SERVER['argv'] = array_slice($_SERVER['argv'], 1); - ConsoleRunner::run($helperSet, []); - } - -} diff --git a/Engine/Console/Commands/Example/ExampleBatchCallCommand.php b/Engine/Console/Commands/Example/ExampleBatchCallCommand.php new file mode 100644 index 0000000..2a6eaad --- /dev/null +++ b/Engine/Console/Commands/Example/ExampleBatchCallCommand.php @@ -0,0 +1,18 @@ +setDescription('Example batch command. Will run subcommand cmd1, cmd3 and group.'); - } - -} diff --git a/Engine/Console/Commands/Example/ExampleCommand1.php b/Engine/Console/Commands/Example/ExampleCommand1.php new file mode 100644 index 0000000..929fc3d --- /dev/null +++ b/Engine/Console/Commands/Example/ExampleCommand1.php @@ -0,0 +1,28 @@ + 'example:cmd1', + 'description' => 'Example command 1', + ]; + + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + $output->writeln($this->getDescription()); + + return self::SUCCESS; + } + +} diff --git a/Engine/Console/Commands/Example/ExampleCommand2.php b/Engine/Console/Commands/Example/ExampleCommand2.php new file mode 100644 index 0000000..f5b1872 --- /dev/null +++ b/Engine/Console/Commands/Example/ExampleCommand2.php @@ -0,0 +1,28 @@ + 'example:cmd2', + 'description' => 'Example command 2', + ]; + + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + $output->writeln($this->getDescription()); + + return self::SUCCESS; + } + +} diff --git a/Engine/Console/Commands/Example/ExampleCommand3.php b/Engine/Console/Commands/Example/ExampleCommand3.php new file mode 100644 index 0000000..52fc230 --- /dev/null +++ b/Engine/Console/Commands/Example/ExampleCommand3.php @@ -0,0 +1,28 @@ + 'example:cmd3', + 'description' => 'Example command 3', + ]; + + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + $output->writeln($this->getDescription()); + + return self::SUCCESS; + } + +} diff --git a/Engine/Console/Commands/Example/ExampleCommandOne.php b/Engine/Console/Commands/Example/ExampleCommandOne.php deleted file mode 100644 index f8dd071..0000000 --- a/Engine/Console/Commands/Example/ExampleCommandOne.php +++ /dev/null @@ -1,31 +0,0 @@ -setDescription('Example command 1'); - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - $output->notice(ExampleCommandOne::class); - } - -} diff --git a/Engine/Console/Commands/Example/ExampleCommandThree.php b/Engine/Console/Commands/Example/ExampleCommandThree.php deleted file mode 100644 index 09c06fc..0000000 --- a/Engine/Console/Commands/Example/ExampleCommandThree.php +++ /dev/null @@ -1,31 +0,0 @@ -setDescription('Example command 3'); - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - $output->notice(ExampleCommandThree::class); - } - -} diff --git a/Engine/Console/Commands/Example/ExampleCommandTwo.php b/Engine/Console/Commands/Example/ExampleCommandTwo.php deleted file mode 100644 index 82d9264..0000000 --- a/Engine/Console/Commands/Example/ExampleCommandTwo.php +++ /dev/null @@ -1,31 +0,0 @@ -setDescription('Example command 2'); - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - $output->notice(ExampleCommandTwo::class); - } - -} diff --git a/Engine/Console/Commands/Example/ExampleGroupCommand.php b/Engine/Console/Commands/Example/ExampleGroupCommand.php deleted file mode 100644 index 7c7d8da..0000000 --- a/Engine/Console/Commands/Example/ExampleGroupCommand.php +++ /dev/null @@ -1,25 +0,0 @@ - '',], self::TYPE_DEVELOPMENT); - $this->setDescription('Example group command. Will run subcommand cmd2 and cmd1.'); - } - -} diff --git a/Engine/Console/Commands/Example/ExampleNamespaceCallCommand.php b/Engine/Console/Commands/Example/ExampleNamespaceCallCommand.php new file mode 100644 index 0000000..891d371 --- /dev/null +++ b/Engine/Console/Commands/Example/ExampleNamespaceCallCommand.php @@ -0,0 +1,18 @@ +setDescription('Display service list'); - $this->addOptions([ - Option::create('e', 'extended')# - ->setDescription('Include service function names')# - ->setDefaultValue(0),# - ]); - } - - /** - * @inheritdoc - * @throws ServiceNotFoundException - */ - public function handle(Input $input, Logger $output) : void { - $isExtended = (bool) $input->getOption('extended'); - $serviceManager = Oforge()->Services(); - $serviceNames = $serviceManager->getServiceNames(); - sort($serviceNames); - $lines = []; - $columnWidth = 0; - foreach ($serviceNames as $serviceName) { - if ($isExtended) { - try { - $service = $serviceManager->get($serviceName); - - $classMethods = get_class_methods($service); - foreach ($classMethods as $classMethod) { - if (StringHelper::startsWith($classMethod, "__")) { - continue; - } - $reflector = new \ReflectionClass($service); - $comment = explode("\n", $reflector->getMethod($classMethod)->getDocComment()); - $methodText = ""; - if (count($comment) > 1) { - if (!StringHelper::contains($comment[1], "@param") - && !StringHelper::contains($comment[1], "@throws") - && !StringHelper::contains($comment[1], "@return")) { - $methodText = strtr($comment[1], [ - '*' => '', - "\n" => '', - ]); - } - } - $serviceFunctionName = $serviceName . ':' . $classMethod; - $columnWidth = max([$columnWidth, strlen($serviceFunctionName)]); - $lines[] = [$serviceFunctionName, $methodText]; - } - } catch (ServiceNotFoundException $e) { - } catch (\ReflectionException $e) { - } - } else { - $columnWidth = max([$columnWidth, strlen($serviceName)]); - $lines[] = [$serviceName, '']; - } - } - - /** @var ConsoleService $consoleService */ - $consoleService = Oforge()->Services()->get('console'); - echo $consoleService->getRenderer()->renderColumns($columnWidth, $lines); - } - -} diff --git a/Engine/Console/Commands/Service/ServiceRunCommand.php b/Engine/Console/Commands/Service/ServiceRunCommand.php deleted file mode 100644 index b786216..0000000 --- a/Engine/Console/Commands/Service/ServiceRunCommand.php +++ /dev/null @@ -1,113 +0,0 @@ -setDescription('Call a specific service function with optional parameters'); - $this->addOperands([ - Operand::create('ServiceNameFunction', Operand::REQUIRED)# - ->setDescription('Name of service & function name (Format: "service-name:function"')# - ->setValidation([$this, 'validateOperandServiceNameFunction'], [$this, 'validationMessageOperandServiceNameFunction']),# - Operand::create('parameters', Operand::MULTIPLE)# - ->setDescription('Parameters of service function'),# - ]); - } - - /** - * Validation message function for validateOperandServiceNameFunction. - * - * @param Operand $operand - * @param $value - * - * @return mixed - */ - public function validationMessageOperandServiceNameFunction(Operand $operand, $value) { - return $this->validationMessage['ServiceNameFunction']; - } - - /** - * Validate operand "ServiceNameFunction" value. - * - * @param $value - * - * @return bool - */ - public function validateOperandServiceNameFunction($value) { - $invalid = (strpos($value, ':') === false); - if ($invalid) { - $this->validationMessage['ServiceNameFunction'] = 'Operand ServiceNameFunction "' . $value . '" has wrong format!'; - } else { - $callable = $this->getServiceFunctionCallable($value); - if ($callable === false) { - $invalid = true; - - $this->validationMessage['ServiceNameFunction'] = 'No Service function "' . $value . '" found!'; - } - } - - return !$invalid; - } - - /** - * @inheritdoc - */ - public function handle(Input $input, Logger $output) : void { - $callable = $this->getServiceFunctionCallable($input->getOperand('ServiceNameFunction')); - if (is_callable($callable)) { - $parameters = $input->getOperand('parameters'); - $return = call_user_func_array($callable, $parameters); - if (!empty($return) || is_numeric($return)) { - $output->notice(is_scalar($return) ? $return : print_r($return, true)); - } - } - } - - /** - * Create service function callable array or error on error. - * - * @param string $serviceNameFunction String of format "serviceName:classFunction". - * - * @return array|bool Callable array or false on error. - */ - private function getServiceFunctionCallable(string $serviceNameFunction) { - $serviceInfos = explode(':', $serviceNameFunction, 2); - $serviceName = $serviceInfos[0]; - $serviceFunction = $serviceInfos[1]; - - try { - $service = Oforge()->Services()->get($serviceName); - $callable = [$service, $serviceFunction]; - if (!is_callable($callable)) { - return false; - } - - return $callable; - } catch (ServiceNotFoundException $e) { - return false; - } - } - -} diff --git a/Engine/Console/ConsoleStatics.php b/Engine/Console/ConsoleStatics.php deleted file mode 100644 index b6e72ac..0000000 --- a/Engine/Console/ConsoleStatics.php +++ /dev/null @@ -1,28 +0,0 @@ -'; - private const TEXT_SURROUND_OPTIONAL = '[]'; - private const TEXT_MULTIPLE = '...'; - /** @var array $settings */ - private $settings = [ - self::SETTING_SCREEN_MAX_WIDTH => self::DEFAULT_SCREEN_WIDTH, - self::SETTING_SHOW_OPTIONS => true, - self::SETTING_SHOW_OPERANDS => true, - self::SETTING_SHOW_USAGE => true, - self::SETTING_SHOW_TITLE_COMMANDS => true, - self::SETTING_SHOW_TITLE_OPTIONS => true, - self::SETTING_SHOW_TITLE_OPERANDS => true, - self::SETTING_SHOW_TITLE_USAGE => true, - self::SETTING_SHOW_USAGE_DESCRIPTION => true, - ]; - /** @var ConsoleService $consoleService */ - private $consoleService; - /** @var GetOpt $getOpt */ - private $getOpt; - /** @var callable $translator */ - private $translator; - - /** - * ConsoleRenderer constructor. - * - * @param ConsoleService $consoleService - * @param GetOpt $getOpt - * @param callable $translator - */ - public function __construct(ConsoleService $consoleService, GetOpt $getOpt, callable $translator) { - $this->consoleService = $consoleService; - $this->getOpt = $getOpt; - $this->translator = $translator; - } - - /** - * Render the help text - * - * @param array $config - * - * @return string - */ - public function renderHelp($config = []) { - $getOpt = $this->getOpt; - foreach ($config as $setting => $value) { - $this->settings[$setting] = $value; - } - $helpText = ''; - if ($this->settings[self::SETTING_SHOW_USAGE]) { - $helpText .= $this->renderUsage(); - } - if ($getOpt->hasOperands() && $this->settings[self::SETTING_SHOW_OPERANDS]) { - $helpText .= $this->renderOperands($getOpt->getOperandObjects()) . PHP_EOL; - } - if ($getOpt->hasOptions() && $this->settings[self::SETTING_SHOW_OPTIONS]) { - $helpText .= $this->renderOptions($getOpt->getOptionObjects()) . PHP_EOL; - } - $commands = $this->consoleService->getCommands(); - if ((count($commands) > 0) && !$getOpt->getCommand()) { - $helpText .= $this->renderCommands($commands); - } - - return $helpText; - } - - /** - * Render 2 column data. Use implode prepareColumns value with PHP_EOL. - * - * @param int $columnWidth - * @param $data [column 0, column 1] - * - * @return string - */ - public function renderColumns($columnWidth, $data) { - $lines = $this->prepareColumns($columnWidth, $data); - - return implode(PHP_EOL, $lines); - } - - /** - * Prepare 2 column data - * - * @param int $columnWidth - * @param $data [column 0, column 1] - * - * @return string[] - */ - public function prepareColumns($columnWidth, $data) { - $screenWidth = $this->getScreenWidth(); - - foreach ($data as &$dataRow) { - $text = ''; - $row = sprintf(' % -' . $columnWidth . 's %s', $dataRow[0], $dataRow[1]); - - while (mb_strlen($row) > $screenWidth) { - $p = strrpos(substr($row, 0, $screenWidth), ' '); - if ($p < $columnWidth + 4) { - // no space - check for dash - $p = strrpos(substr($row, 0, $screenWidth), '-'); - if ($p < $columnWidth + 4) { - // break at screen width - $p = $screenWidth - 1; - } - } - $c = substr($row, $p, 1); - $text .= substr($row, 0, $p) . ($c !== ' ' ? $c : '') . PHP_EOL; - $row = sprintf(' %s %s', str_repeat(' ', $columnWidth), substr($row, $p + 1)); - } - $dataRow = $row; - } - - return $data; - } - - /** - * @param Command[] $commands - * @param bool $showTitle - * - * @return string - */ - public function renderCommands($commands, $showTitle = true) { - $data = []; - $columnWidth = 0; - foreach ($commands as $command) { - $columnWidth = max([$columnWidth, strlen($command->getName())]); - - $data[] = [ - $command->getName(), - $this->translate($command->getShortDescription()), - ]; - } - - return $this->renderSection($this->settings[self::SETTING_SHOW_TITLE_COMMANDS] && $showTitle, $this->translate('Commands') . ':' . PHP_EOL, - $columnWidth, $data); - } - - /** - * @param Operand[] $operands - * - * @return string - */ - private function renderOperands($operands) { - $data = []; - $columnWidth = 0; - foreach ($operands as $operand) { - $definition = $this->surround($operand->getName(), self::TEXT_SURROUND_PLACEHOLDER); - if (!$operand->isRequired()) { - $definition = $this->surround($definition, self::TEXT_SURROUND_OPTIONAL); - } - - $columnWidth = max([$columnWidth, strlen($definition)]); - - $data[] = [ - $definition, - $this->translate($operand->getDescription()), - ]; - } - - return $this->renderSection($this->settings[self::SETTING_SHOW_TITLE_OPERANDS], $this->translate('Operands') . ':' . PHP_EOL, $columnWidth, $data); - } - - /** - * @param Option[] $options - * - * @return string - */ - private function renderOptions($options) { - $data = []; - $columnWidth = 0; - foreach ($options as $option) { - $definition = implode(', ', array_filter([ - $option->getShort() ? '-' . $option->getShort() : null, - $option->getLong() ? '--' . $option->getLong() : null, - ])); - if (!$option->getShort()) { - $definition = ' ' . $definition; - } - - if ($option->getMode() !== GetOpt::NO_ARGUMENT) { - $argument = $this->surround($option->getArgument()->getName(), self::TEXT_SURROUND_PLACEHOLDER); - if ($option->getMode() === GetOpt::OPTIONAL_ARGUMENT) { - $argument = $this->surround($argument, self::TEXT_SURROUND_OPTIONAL); - } - - $definition .= ' ' . $argument; - } - - $columnWidth = max([$columnWidth, strlen($definition)]); - - $data[] = [ - $definition, - $this->translate($option->getDescription()), - ]; - } - - return $this->renderSection($this->settings[self::SETTING_SHOW_TITLE_OPTIONS], $this->translate('Options') . ':' . PHP_EOL, $columnWidth, $data); - } - - /** - * @return string - */ - private function renderUsage() { - $text = $this->translate('Usage') . ': ' . $this->getOpt->get(GetOpt::SETTING_SCRIPT_NAME) . ' '; - $command = $this->getOpt->getCommand(); - // command - if ($command) { - $text .= $command->getName() . ' '; - } elseif ($this->getOpt->hasCommands()) { - $text .= $this->surround($this->translate('command'), self::TEXT_SURROUND_PLACEHOLDER) . ' '; - } - // options - if ($this->getOpt->hasOptions() || !$this->getOpt->get(GetOpt::SETTING_STRICT_OPTIONS)) { - $text .= $this->surround($this->translate('options'), self::TEXT_SURROUND_OPTIONAL) . ' '; - } - // operands - if ($this->getOpt->hasOperands()) { - $lastOperandMultiple = false; - foreach ($this->getOpt->getOperandObjects() as $operand) { - $name = $this->surround($operand->getName(), self::TEXT_SURROUND_PLACEHOLDER); - if (!$operand->isRequired()) { - $name = $this->surround($name, self::TEXT_SURROUND_OPTIONAL); - } - $text .= $name . ' '; - if ($operand->isMultiple()) { - $text .= $this->surround($this->surround($operand->getName(), self::TEXT_SURROUND_PLACEHOLDER) . self::TEXT_MULTIPLE, - self::TEXT_SURROUND_OPTIONAL); - - $lastOperandMultiple = true; - } - } - if (!$lastOperandMultiple && !$this->getOpt->get(GetOpt::SETTING_STRICT_OPERANDS)) { - $text .= $this->surround($this->translate('operands'), self::TEXT_SURROUND_OPTIONAL); - } - } - if ($this->settings[self::SETTING_SHOW_USAGE_DESCRIPTION]) { - if ($command) { - $text .= PHP_EOL . PHP_EOL . $this->translate($command->getDescription()); - } - } - - return $text . PHP_EOL . PHP_EOL; - } - - /** - * Try to get console with. - * - * @return int - */ - private function getScreenWidth() { - if (!isset($this->settings[self::SETTING_SCREEN_WIDTH])) { - $columns = defined('COLUMNS') ? (int) COLUMNS : (int) @getenv('COLUMNS'); - if (empty($columns)) { - $process = proc_open('tput cols', [ - 1 => ['pipe', 'w'], - 2 => ['pipe', 'w'], - ], $pipes); - $columns = (int) stream_get_contents($pipes[1]); - proc_close($process); - } - - if (empty($columns) && class_exists('\\Symfony\\Component\\Console\\Terminal')) { - $terminal = new \Symfony\Component\Console\Terminal(); - $columns = $terminal->getWidth(); - } - - $columns = empty($columns) ? self::SETTING_SCREEN_MAX_WIDTH : $columns; - - $this->settings[self::SETTING_SCREEN_WIDTH] = $columns; - } - - return $this->settings[self::SETTING_SCREEN_WIDTH]; - } - - /** - * Render section with optional title. - * - * @param $showTitle - * @param $title - * @param $columnWidth - * @param $data - * - * @return string - */ - private function renderSection($showTitle, $title, $columnWidth, $data) { - if (!$showTitle) { - $title = ''; - } - - return $title . $this->renderColumns($columnWidth, $data) . PHP_EOL; - } - - /** - * Surround text with symbols. - * - * @param $text - * @param $with - * - * @return string - */ - private function surround($text, $with) { - return $with[0] . $text . substr($with, -1); - } - - /** - * Translator method - * - * @param string $string - * - * @return mixed - */ - private function translate(string $string) { - $translator = $this->translator; - - return $translator($string); - } - -} diff --git a/Engine/Console/Lib/Input.php b/Engine/Console/Lib/Input.php deleted file mode 100644 index f7882f4..0000000 --- a/Engine/Console/Lib/Input.php +++ /dev/null @@ -1,108 +0,0 @@ -getOperandObjects() as $operand) { - $name = $operand->getName(); - $value = $operand->getValue(); - - $operandValues[$index++] = $value; - if (isset($name) && $name !== 'arg') { - $operandValues[$name] = $value; - } - } - - $this->operands = $operandValues; - $this->options = $getOpt->getOptions(); - } - - /** - * Is option by $name set. - * - * @param string $name Short or long name of the option - * - * @return bool - */ - public function hasOption($name) { - return isset($this->options[$name]); - } - - /** - * Get an option by $name or null. - * - * @param string $name Short or long name of the option - * - * @return mixed|null - */ - public function getOption($name) { - return $this->options[$name] ?? null; - } - - /** - * Returns the list of options with a value. - * - * @return array - */ - public function getOptions() { - return $this->options; - } - - /** - * Is operand by $index set. - * - * @param int|string $index - * - * @return bool - */ - public function hasOperand($index) { - return isset($this->operands[$index]); - } - - /** - * Returns the nth operand (starting with 0), or null if it does not exist. - * When $index is a string it returns the current value or the default value for the named operand. - * - * @param int|string $index - * - * @return mixed - */ - public function getOperand($index) { - return $this->operands[$index] ?? null; - } - - /** - * Returns the list of operands. Must be invoked after parse(). - * - * @return array - */ - public function getOperands() { - return $this->operands; - } - -} diff --git a/Engine/Console/Lib/Monolog/Formatter/ConsoleFormatter.php b/Engine/Console/Lib/Monolog/Formatter/ConsoleFormatter.php deleted file mode 100644 index bb7f05f..0000000 --- a/Engine/Console/Lib/Monolog/Formatter/ConsoleFormatter.php +++ /dev/null @@ -1,33 +0,0 @@ -ignoreEmptyContextAndExtra(); - $this->allowInlineLineBreaks(); - $this->includeStacktraces(); - } - - /** - * @param string $format - */ - public function setFormat(string $format) : void { - $this->format = $format; - } - -} diff --git a/Engine/Console/Managers/ConsoleManager.php b/Engine/Console/Managers/ConsoleManager.php new file mode 100644 index 0000000..8b988bb --- /dev/null +++ b/Engine/Console/Managers/ConsoleManager.php @@ -0,0 +1,113 @@ + $commandClasses */ + private static $commandClasses = []; + /** @var Application $application */ + private $application; + /** @var ConsoleOutput $output */ + private $output; + /** @var ConsoleOutput $nullOutput */ + private $nullOutput; + + /** + * ConsoleManager constructor. + */ + public function __construct() { + $application = new Application(); + $application->addCommands($this->collectCommands()); + $this->application = $application; + $this->output = new ConsoleOutput(); + } + + /** + * @return ConsoleManager + */ + public static function init() : ConsoleManager { + if (!isset(self::$instance)) { + self::$instance = new ConsoleManager(); + } + + return self::$instance; + } + + /** + * @param string[] $commandClasses + * + * @throws InvalidClassException + */ + public static function registerCommandClasses($commandClasses) { + foreach ($commandClasses as $commandClass) { + if (!is_subclass_of($commandClass, Command::class)) { + throw new InvalidClassException($commandClass, Command::class); + } + if (!isset(self::$commandClasses[$commandClass])) { + self::$commandClasses[$commandClass] = 1; + } + } + } + + /** + * @throws \Exception + */ + public function run() { + $output = $this->application->run(null, $this->output); + } + + /** + * @param string $name + * @param string|array $args $args + * @param bool $consoleOutput + * + * @return int + * @throws \Exception + */ + public function callCommand(string $name, $args, bool $consoleOutput = true) { + $command = $this->application->find($name); + if (is_string($args)) { + $args = new StringInput($args); + } elseif (is_array($args)) { + $args = new ArrayInput($args); + } + if (!isset($this->nullOutput)) { + $this->nullOutput = new NullOutput(); + } + $output = $consoleOutput ? $this->output : $this->nullOutput; + + return $command->run($args, $output); + } + + /** + * @return Command[] + */ + protected function collectCommands() { + $commands = []; + foreach (self::$commandClasses as $commandClass => $any) { + /** @var Command $command */ + $command = new $commandClass(); + + $commands[$command->getName()] = $command; + } + ksort($commands); + + return $commands; + } + +} diff --git a/Engine/Console/Services/ConsoleService.php b/Engine/Console/Services/ConsoleService.php deleted file mode 100644 index 758cb2d..0000000 --- a/Engine/Console/Services/ConsoleService.php +++ /dev/null @@ -1,319 +0,0 @@ -setFormatter($this->loggerFormatter); - $this->outputLogger->pushHandler($handler); - } - - /** - * Remove handler from output logger. - * - * @param HandlerInterface $handler - */ - public function removeOutputLoggerHandler(HandlerInterface $handler) : void { - $handlers = $this->outputLogger->getHandlers(); - $key = array_search($handler, $handlers); - if ($key !== false) { - unset($handlers[$key]); - } - $this->outputLogger->setHandlers($handlers); - } - - /** - * @return ConsoleRenderer - */ - public function getRenderer() : ConsoleRenderer { - return $this->consoleRenderer; - } - - /** - * Get list of all (filtered) commands. - * List can be filtered by CommandType. - * - * @see CommandType - * - * @param int $type Bitmask consisting of AbstractCommand type values, except AbstractCommand::TYPE_HIDDEN. [Default: AbstractCommand::TYPE_DEFAULT] - * - * @return \GetOpt\Command[] - */ - public function getCommands(int $type = AbstractCommand::TYPE_DEFAULT) { - if (is_null($this->getOpt)) { - $this->init(); - } - - if (BitmaskHelper::is($type, AbstractCommand::TYPE_HIDDEN)) { - $type = AbstractCommand::TYPE_DEFAULT; - } - $commands = $this->getOpt->getCommands(); - if ($type !== AbstractCommand::ALL_TYPES) { - $commands = array_filter($commands, function ($command) use ($type) { - if (is_subclass_of($command, AbstractCommand::class)) { - /** - * @var AbstractCommand $command - */ - return (BitmaskHelper::is($command->getType(), $type)); - } - - return true; - }); - } - - return $commands; - } - - /** - * Run command with argument string. - * - * @param string $command - * @param string $args - */ - public function runCommand(string $command, string $args = '') : void { - $firstRun = false; - if (!isset($this->getOpt)) { - $this->init(); - $firstRun = true; - } - $getOpt = $this->getOpt; - try { - try { - - $getOpt->process(trim($command . ' ' . $args)); - } catch (ArgumentException\Missing $exception) { - // catch missing exceptions if help is requested - if (!$getOpt->getOption('help')) { - throw $exception; - } - } - } catch (ArgumentException $exception) { - file_put_contents('php://stderr', $exception->getMessage() . PHP_EOL); - echo PHP_EOL, $this->consoleRenderer->renderHelp(); - exit(); - } - $command = $getOpt->getCommand(); - if ($firstRun) { - if ($getOpt->getOption('help') || !$command) { - echo $this->consoleRenderer->renderHelp(); - exit(); - } - $this->evaluateGlobalOptionLogtime(); - $this->evaluateGlobalOptionLogfile($command); - $this->evaluateGlobalOptionVerbose(); - } - $input = new Input($getOpt); - // call the requested command - call_user_func($command->getHandler(), $input, $this->outputLogger); - } - - /** - * Init ConsoleService. - * Collect and create commands from modules and plugin. - */ - public function init() { - if (isset($this->getOpt)) { - return; - } - $this->outputLogger = new Logger('console'); - $this->loggerFormatter = new ConsoleFormatter(self::LOG_FORMAT_NO_TIME); - try { - $handler = new StreamHandler('php://stdout', Logger::DEBUG); - $this->addOutputLoggerHandler($handler); - } catch (\Exception $exception) { - Oforge()->Logger()->get()->error($exception->getMessage(), $exception->getTrace()); - } - $getOpt = new GetOpt(null, [ - \GetOpt\GetOpt::SETTING_STRICT_OPTIONS => false, - ]); - $getOpt->addOptions([ - Option::create(null, 'help', GetOpt::NO_ARGUMENT)# - ->setDescription('Display this help message'), - Option::create('v', 'verbose', GetOpt::OPTIONAL_ARGUMENT)# - ->setDescription('Increase the verbosity of messages: 1 (v) for normal output, 2 (vv) for more verbose output and 3 (vvv) for debug')# - ->setDefaultValue(1), - Option::create(null, 'logtime', GetOpt::NO_ARGUMENT)# - ->setDescription('Include time in in logger output [Default: none]'), - Option::create(null, 'logfile', GetOpt::NO_ARGUMENT)# - ->setDescription('Include file handler in logger[Default: none]'), - ]); - $commands = $this->collectCommands(); - usort($commands, function ($c1, $c2) { - /** - * @var AbstractCommand $c1 - * @var AbstractCommand $c2 - */ - return strcmp($c1->getName(), $c2->getName()); - }); - $getOpt->addCommands($commands); - $this->getOpt = $getOpt; - - $this->consoleRenderer = new ConsoleRenderer($this, $getOpt, function ($string) { - return $string; // TODO use oforge translation function - }); - } - - /** - * Collect command class names of active modules and plugins. - * - * @return AbstractCommand[] - */ - protected function collectCommands() { - $commandInstances = []; - $commandClassNames = []; - - // TODO refactor after boostrap refactoring - $entityManager = Oforge()->DB()->getForgeEntityManager(); - $moduleRepository = $entityManager->getRepository(Module::class); - $pluginRepository = $entityManager->getRepository(Plugin::class); - /** - * @var Module[] $modules - */ - $modules = $moduleRepository->findBy(['active' => 1], ['order' => 'ASC']); - $moduleRepository->clear(); - foreach ($modules as $module) { - $bootstrapName = $module->getName(); - /** - * @var AbstractBootstrap $instance - */ - $instance = new $bootstrapName(); - $commandClassNames = array_merge($commandClassNames, $instance->getCommands()); - } - /** - * @var Plugin[] $plugins - */ - $plugins = $pluginRepository->findBy(['active' => 1], ['order' => 'ASC']); - $pluginRepository->clear(); - foreach ($plugins as $plugin) { - $bootstrapName = $plugin->getName() . '\Bootstrap'; - /** - * @var AbstractBootstrap $instance - */ - $instance = new $bootstrapName(); - $commandClassNames = array_merge($commandClassNames, $instance->getCommands()); - } - - foreach ($commandClassNames as $commandClassName) { - if (is_subclass_of($commandClassName, AbstractCommand::class)) { - $commandInstances[] = new $commandClassName(); - } - } - - return $commandInstances; - } - - /** - * Evaluate global option --logtime. - */ - protected function evaluateGlobalOptionLogtime() : void { - if ($this->getOpt->getOption('logtime')) { - $this->loggerFormatter->setFormat(self::LOG_FORMAT_WITH_TIME); - } - } - - /** - * Evaluate global option --logfile. - * - * @param Command $command - */ - protected function evaluateGlobalOptionLogfile(Command $command) : void { - if ($this->getOpt->getOption('logfile') && !is_null($command)) { - $filePath = ConsoleStatics::CONSOLE_LOGS_DIR_ABS . DIRECTORY_SEPARATOR . str_replace(':', '_', $command->getName()) . '.log'; - $maxFiles = 14; - - $this->addOutputLoggerHandler(new RotatingFileHandler($filePath, $maxFiles, Logger::DEBUG)); - } - } - - /** - * Evaluate global option --verbose|-v. - */ - protected function evaluateGlobalOptionVerbose() : void { - $verbose = $this->getOpt->getOption('verbose'); - if (!is_numeric($verbose)) { - $verbose = 1 + substr_count($verbose, 'v'); - } - switch ($verbose) { - case 1: - $loggerLevel = Logger::NOTICE; - break; - case 2: - $loggerLevel = Logger::INFO; - break; - case 3: - default: - $loggerLevel = Logger::DEBUG; - break; - } - $loggerHandlers = $this->outputLogger->getHandlers(); - foreach ($loggerHandlers as $loggerHandler) { - if (is_subclass_of($loggerHandler, AbstractHandler::class)) { - /** - * @var AbstractHandler $loggerHandler - */ - $loggerHandler->setLevel($loggerLevel); - } - } - } - -} diff --git a/bin/console b/bin/console index 2a61975..e166949 100644 --- a/bin/console +++ b/bin/console @@ -1,14 +1,2 @@ forge(false); - -/** - * @var \Oforge\Engine\Modules\Console\Services\ConsoleService $consoleService - */ -$consoleService = Oforge()->Services()->get( 'console'); -$consoleService->runCommand( '', join( ' ', array_slice($argv, 1))); +require_once __DIR__ . '/php/console.php'; diff --git a/bin/doctrine b/bin/doctrine new file mode 100644 index 0000000..2f50943 --- /dev/null +++ b/bin/doctrine @@ -0,0 +1,2 @@ +forge(false); + +\Oforge\Engine\Console\Managers\ConsoleManager::init()->run(); diff --git a/bin/php/doctrine.php b/bin/php/doctrine.php new file mode 100644 index 0000000..9bd2cbd --- /dev/null +++ b/bin/php/doctrine.php @@ -0,0 +1,17 @@ +forge(false); + +/** @var EntityManager $entityManager */ +$entityManager = Oforge()->DB()->getForgeEntityManager()->getEntityManager(); +$helperSet = ConsoleRunner::createHelperSet($entityManager); +$helperSet->set(new ConnectionHelper($entityManager->getConnection()), 'db'); +$helperSet->set(new EntityManagerHelper($entityManager), 'em'); +ConsoleRunner::run($helperSet, []); diff --git a/composer.json b/composer.json index 751e4ab..5b1d67b 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,6 @@ "php-di/slim-bridge": "^2.0", "doctrine/orm":"^2.0", "firebase/php-jwt": "^5.0", - "ulrichsg/getopt-php": "^3.0", "marcj/topsort": "^1.1", "ext-fileinfo": "*", "wikimedia/composer-merge-plugin": "*" From c9eb95f322832b7924e80034de6ebd16b1e0e0d8 Mon Sep 17 00:00:00 2001 From: FK Date: Thu, 29 Oct 2020 15:12:13 +0100 Subject: [PATCH 03/11] Remove template bootstrap search & caching --- Engine/Core/Helper/FileSystemHelper.php | 11 --------- Engine/Core/Helper/Statics.php | 1 - .../Manager/Bootstrap/BootstrapManager.php | 23 +++---------------- 3 files changed, 3 insertions(+), 32 deletions(-) diff --git a/Engine/Core/Helper/FileSystemHelper.php b/Engine/Core/Helper/FileSystemHelper.php index db5057a..dd47343 100644 --- a/Engine/Core/Helper/FileSystemHelper.php +++ b/Engine/Core/Helper/FileSystemHelper.php @@ -182,17 +182,6 @@ public static function getBootstrapFiles(string $path) { return self::getCachedOrFind($path, 'bootstrap.php'); } - /** - * Get all template files inside a defined path - * - * @param string $path - * - * @return string[] - */ - public static function getThemeBootstrapFiles(string $path) { - return self::getCachedOrFind($path, 'template.php'); - } - /** * Get all sub directories recursive based on the defined path, except the folders to oforge omit. * diff --git a/Engine/Core/Helper/Statics.php b/Engine/Core/Helper/Statics.php index db66b2d..e224059 100644 --- a/Engine/Core/Helper/Statics.php +++ b/Engine/Core/Helper/Statics.php @@ -33,5 +33,4 @@ class Statics { public const MODULES_DIR = 'Modules'; public const PLUGIN_DIR = 'Plugins'; // public const VIEW_DIR = 'Views'; - public const TEMPLATE_DIR = 'Themes'; } diff --git a/Engine/Core/Manager/Bootstrap/BootstrapManager.php b/Engine/Core/Manager/Bootstrap/BootstrapManager.php index e3aef70..13c3f2f 100644 --- a/Engine/Core/Manager/Bootstrap/BootstrapManager.php +++ b/Engine/Core/Manager/Bootstrap/BootstrapManager.php @@ -17,7 +17,7 @@ */ class BootstrapManager { - private const FILE_PATH = ROOT_PATH . Statics::DIR_CACHE . Statics::GLOBAL_SEPARATOR . 'bootstrap.php'; + private const FILE_PATH = ROOT_PATH . Statics::DIR_CACHE . Statics::GLOBAL_SEPARATOR . 'bootstrap.cache.php'; public const KEY_PATH = 'path'; public const KEY_NS = 'namespace'; /** @var BootstrapManager $instance */ @@ -87,15 +87,6 @@ public function getPluginBootstrapData() return $this->bootstrapData[Statics::PLUGIN_DIR]; } - /** - * Returns theme bootstrap data. - * - * @return mixed - */ - public function getThemeBootstrapData() - { - return $this->bootstrapData[Statics::TEMPLATE_DIR]; - } /** * Initialize all modules and plugins bootstrap data. @@ -168,7 +159,6 @@ protected function collectBootstrapData() $bootstrapData = [ Statics::ENGINE_DIR => $this->collectBootstrapDataSub(Statics::ENGINE_DIR), Statics::PLUGIN_DIR => $this->collectBootstrapDataSub(Statics::PLUGIN_DIR), - Statics::TEMPLATE_DIR => $this->collectBootstrapDataSub(Statics::TEMPLATE_DIR), ]; $this->bootstrapData = $bootstrapData; @@ -185,24 +175,17 @@ protected function collectBootstrapDataSub(string $context) { $isModule = $context === Statics::ENGINE_DIR; $isPlugin = $context === Statics::PLUGIN_DIR; - $isTheme = $context === Statics::TEMPLATE_DIR; $data = []; - if ($isTheme) { - $files = FileSystemHelper::getThemeBootstrapFiles(ROOT_PATH . Statics::GLOBAL_SEPARATOR . $context); - } else { - $files = FileSystemHelper::getBootstrapFiles(ROOT_PATH . Statics::GLOBAL_SEPARATOR . $context); - } + $files = FileSystemHelper::getBootstrapFiles(ROOT_PATH . Statics::GLOBAL_SEPARATOR . $context); foreach ($files as $file) { $directory = dirname($file); - $class = str_replace('/', '\\', str_replace(ROOT_PATH, '', $directory)) . ($isTheme ? '\Template' : '\Bootstrap'); + $class = str_replace('/', '\\', str_replace(ROOT_PATH, '', $directory)) . '\Bootstrap'; $class = 'Oforge'.$class; if ($isModule || $isPlugin) { $namespace = StringHelper::rightTrim($class, '\\Bootstrap'); - } elseif ($isTheme) { - $namespace = StringHelper::rightTrim($class, '\\Template'); } $class = StringHelper::leftTrim($class, '\\'); From 81c97ae68c55156903e9137e396b8dd2073dc56d Mon Sep 17 00:00:00 2001 From: FK Date: Thu, 29 Oct 2020 15:26:51 +0100 Subject: [PATCH 04/11] Bugfixes --- .../Abstracts/AbstractBatchCallCommand.php | 2 +- Engine/Console/Abstracts/AbstractCommand.php | 21 +++++++++++++++---- .../AbstractNamespaceCallCommand.php | 6 +++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Engine/Console/Abstracts/AbstractBatchCallCommand.php b/Engine/Console/Abstracts/AbstractBatchCallCommand.php index e58cd52..c7da8f2 100644 --- a/Engine/Console/Abstracts/AbstractBatchCallCommand.php +++ b/Engine/Console/Abstracts/AbstractBatchCallCommand.php @@ -55,7 +55,7 @@ protected function configure() { */ protected function execute(InputInterface $input, OutputInterface $output) : int { $this->checkBatchCallConfig(); - $stopOnError = $this->getDefinition()->hasOption(self::OPTION_STOP_ON_ERROR) && $input->hasOption(self::OPTION_STOP_ON_ERROR); + $stopOnError = $input->getOption(self::OPTION_STOP_ON_ERROR); foreach ($this->commands as $name => $args) { if (!is_string($name)) { $name = $args; diff --git a/Engine/Console/Abstracts/AbstractCommand.php b/Engine/Console/Abstracts/AbstractCommand.php index 8b67697..2401634 100644 --- a/Engine/Console/Abstracts/AbstractCommand.php +++ b/Engine/Console/Abstracts/AbstractCommand.php @@ -46,6 +46,7 @@ abstract class AbstractCommand extends Command { * @var array $config */ protected $config = []; + private $logger = null; /** @inheritdoc */ protected function configure() { @@ -84,10 +85,10 @@ protected function configure() { } if (isset($config['options']) && is_array($config['options'])) { foreach ($config['options'] as $optionName => $optionConfig) { - $shortcut = $argumentConfig['shortcut'] ?? null; - $mode = $argumentConfig['mode'] ?? InputOption::VALUE_NONE; - $description = $argumentConfig['description'] ?? ''; - $default = $argumentConfig['default'] ?? null; + $shortcut = $optionConfig['shortcut'] ?? null; + $mode = $optionConfig['mode'] ?? InputOption::VALUE_NONE; + $description = $optionConfig['description'] ?? ''; + $default = $optionConfig['default'] ?? null; if ($mode === InputOption::VALUE_NONE) { $default = null; } @@ -116,4 +117,16 @@ protected function callOtherCommand(OutputInterface $output, string $name, $args return $command->run($args, $output); } + // protected function getLogger(OutputInterface $output) { //not working yet, TODO howto combine of $output & logger + // if ($this->logger === null) { + // // $consoleLogger = new ConsoleLogger($output); + // // + // // $consoleLogger-> + // // + // // $this->logger = $consoleLogger; + // } + // + // return $this->logger; + // } + } diff --git a/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php b/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php index e222c4a..288ea0a 100644 --- a/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php +++ b/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php @@ -26,7 +26,7 @@ abstract class AbstractNamespaceCallCommand extends AbstractCommand { * * @var string[] $excludeCommands */ - protected $excludeCommands; + protected $excludeCommands = []; /** * AbstractNamespaceCallCommand constructor. @@ -44,7 +44,7 @@ public function __construct(string $namespace = null, array $excludeCommands = [ /** @inheritdoc */ protected function configure() { $this->addOption(self::OPTION_STOP_ON_ERROR, null, InputOption::VALUE_NONE, 'Quit when a subcommand fails.'); - $this->setDescription('Call all commands of namespace: ' . $this->namespace); + $this->setDescription('Call all commands of namespace: "' . $this->namespace . '"'); parent::configure(); } @@ -54,7 +54,7 @@ protected function configure() { */ protected function execute(InputInterface $input, OutputInterface $output) : int { $this->checNamespaceCallConfig(); - $stopOnError = $this->getDefinition()->hasOption(self::OPTION_STOP_ON_ERROR) && $input->hasOption(self::OPTION_STOP_ON_ERROR); + $stopOnError = $input->getOption(self::OPTION_STOP_ON_ERROR); $commands = $this->getApplication()->all($this->namespace); if (!is_array($commands)) { $commands = [$commands]; From 76ee977757f9a31880952996b026da87a7583cd7 Mon Sep 17 00:00:00 2001 From: FK Date: Thu, 29 Oct 2020 15:27:11 +0100 Subject: [PATCH 05/11] Adding commands --- Engine/Console/Bootstrap.php | 20 ++- .../Cleanup/Cache/BootstrapCommand.php | 49 +++++++ .../Cleanup/Cache/DoctrineProxyCommand.php | 37 +++++ .../Cleanup/Cache/NamespaceCallCommand.php | 16 +++ .../Commands/Cleanup/LogFilesCommand.php | 42 ++++++ .../Dev/Cleanup/Cache/DoctrineCommand.php | 37 +++++ ...chCallCommand.php => BatchCallCommand.php} | 2 +- .../{ExampleCommand1.php => Command1.php} | 2 +- .../{ExampleCommand2.php => Command2.php} | 2 +- .../{ExampleCommand3.php => Command3.php} | 2 +- ...llCommand.php => NamespaceCallCommand.php} | 4 +- .../Commands/{Core => Oforge}/PingCommand.php | 2 +- .../ProcessAsyncEventsCommand.php | 9 +- .../Commands/Oforge/ServiceCommand.php | 131 ++++++++++++++++++ 14 files changed, 336 insertions(+), 19 deletions(-) create mode 100644 Engine/Console/Commands/Cleanup/Cache/BootstrapCommand.php create mode 100644 Engine/Console/Commands/Cleanup/Cache/DoctrineProxyCommand.php create mode 100644 Engine/Console/Commands/Cleanup/Cache/NamespaceCallCommand.php create mode 100644 Engine/Console/Commands/Cleanup/LogFilesCommand.php create mode 100644 Engine/Console/Commands/Dev/Cleanup/Cache/DoctrineCommand.php rename Engine/Console/Commands/Example/{ExampleBatchCallCommand.php => BatchCallCommand.php} (86%) rename Engine/Console/Commands/Example/{ExampleCommand1.php => Command1.php} (93%) rename Engine/Console/Commands/Example/{ExampleCommand2.php => Command2.php} (93%) rename Engine/Console/Commands/Example/{ExampleCommand3.php => Command3.php} (93%) rename Engine/Console/Commands/Example/{ExampleNamespaceCallCommand.php => NamespaceCallCommand.php} (67%) rename Engine/Console/Commands/{Core => Oforge}/PingCommand.php (94%) rename Engine/Console/Commands/{Core => Oforge}/ProcessAsyncEventsCommand.php (70%) create mode 100644 Engine/Console/Commands/Oforge/ServiceCommand.php diff --git a/Engine/Console/Bootstrap.php b/Engine/Console/Bootstrap.php index f86e59d..78296ab 100644 --- a/Engine/Console/Bootstrap.php +++ b/Engine/Console/Bootstrap.php @@ -18,13 +18,19 @@ class Bootstrap extends AbstractBootstrap { */ public function __construct() { $this->setConfiguration('commands', [ - Commands\Core\PingCommand::class, - Commands\Core\ProcessAsyncEventsCommand::class, - Commands\Example\ExampleBatchCallCommand::class, - Commands\Example\ExampleCommand1::class, - Commands\Example\ExampleCommand2::class, - Commands\Example\ExampleCommand3::class, - Commands\Example\ExampleNamespaceCallCommand::class, + Commands\Oforge\PingCommand::class, + Commands\Oforge\ProcessAsyncEventsCommand::class, + Commands\Oforge\ServiceCommand::class, + Commands\Cleanup\LogFilesCommand::class, + Commands\Cleanup\Cache\BootstrapCommand::class, + Commands\Cleanup\Cache\DoctrineProxyCommand::class, + Commands\Cleanup\Cache\NamespaceCallCommand::class, + Commands\Dev\Cleanup\Cache\DoctrineCommand::class, + Commands\Example\BatchCallCommand::class, + Commands\Example\Command1::class, + Commands\Example\Command2::class, + Commands\Example\Command3::class, + Commands\Example\NamespaceCallCommand::class, ]); Oforge()->Events()->attach('Oforge:Extension:init', Event::SYNC, function(Event $event) { diff --git a/Engine/Console/Commands/Cleanup/Cache/BootstrapCommand.php b/Engine/Console/Commands/Cleanup/Cache/BootstrapCommand.php new file mode 100644 index 0000000..78298f7 --- /dev/null +++ b/Engine/Console/Commands/Cleanup/Cache/BootstrapCommand.php @@ -0,0 +1,49 @@ + 'cleanup:cache:bootstrap', + 'description' => 'Remove bootstrap cache file', + ]; + + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + $directory = ROOT_PATH . Statics::DIR_CACHE . Statics::GLOBAL_SEPARATOR; + + $success = true; + if (file_exists($directory . 'bootstrap.cache.php')) { + // $success &= FileSystemHelper::remove($directory . 'bootstrap.cache'); + $success &= FileSystemHelper::remove($directory . 'bootstrap.cache.php'); + } + //region Old caching files, TODO remove after core refactoring + $success &= FileSystemHelper::remove($directory . 'Engine.cache'); + $success &= FileSystemHelper::remove($directory . 'Engine.cache.php'); + $success &= FileSystemHelper::remove($directory . 'Plugins.cache'); + $success &= FileSystemHelper::remove($directory . 'Plugins.cache.php'); + //endregion + + if ($success) { + $output->writeln('Removed bootstrap cache file.', OutputInterface::VERBOSITY_NORMAL); + + return self::SUCCESS; + } + $output->writeln('Bootstrap cache file could not be cleared.', OutputInterface::VERBOSITY_NORMAL); + + return self::FAILURE; + } + +} diff --git a/Engine/Console/Commands/Cleanup/Cache/DoctrineProxyCommand.php b/Engine/Console/Commands/Cleanup/Cache/DoctrineProxyCommand.php new file mode 100644 index 0000000..6de5079 --- /dev/null +++ b/Engine/Console/Commands/Cleanup/Cache/DoctrineProxyCommand.php @@ -0,0 +1,37 @@ + 'cleanup:cache:proxy', + 'description' => 'Remove doctrine proxy cache folder', + ]; + + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + $directory = ROOT_PATH . Statics::DIR_CACHE_PROXY; + + if (FileSystemHelper::remove($directory, true)) { + $output->writeln('Doctrine proxy cache directory cleared.', OutputInterface::VERBOSITY_NORMAL); + + return self::SUCCESS; + } + $output->writeln('Doctrine proxy cache directory could not be cleared.', OutputInterface::VERBOSITY_NORMAL); + + return self::FAILURE; + } + +} diff --git a/Engine/Console/Commands/Cleanup/Cache/NamespaceCallCommand.php b/Engine/Console/Commands/Cleanup/Cache/NamespaceCallCommand.php new file mode 100644 index 0000000..ba657a6 --- /dev/null +++ b/Engine/Console/Commands/Cleanup/Cache/NamespaceCallCommand.php @@ -0,0 +1,16 @@ + 'cleanup:logs', + 'description' => 'Cleanup log files', + 'options' => [ + 'days' => [ + 'shortcut' => 'd', + 'mode' => InputOption::VALUE_OPTIONAL, + 'description' => 'Remove files older x days', + 'default' => LoggerManager::DEFAULT_DAYS_LIMIT, + ], + ], + ]; + + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + $days = $input->getOption('days'); + if (is_numeric($days)) { + Oforge()->Logger()->cleanupLogFiles((int) $days); + } else { + Oforge()->Logger()->cleanupLogFiles(); + } + + return self::SUCCESS; + } +} diff --git a/Engine/Console/Commands/Dev/Cleanup/Cache/DoctrineCommand.php b/Engine/Console/Commands/Dev/Cleanup/Cache/DoctrineCommand.php new file mode 100644 index 0000000..de95633 --- /dev/null +++ b/Engine/Console/Commands/Dev/Cleanup/Cache/DoctrineCommand.php @@ -0,0 +1,37 @@ + 'dev:cleanup:cache:doctrine', + 'description' => 'Remove doctrine orm cache folder', + ]; + + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + $directory = ROOT_PATH . Statics::DIR_CACHE_DB; + + if (FileSystemHelper::remove($directory, true)) { + $output->writeln('Doctrine cache directory cleared.', OutputInterface::VERBOSITY_NORMAL); + + return self::SUCCESS; + } + $output->writeln('Doctrine cache directory could not be cleared.', OutputInterface::VERBOSITY_NORMAL); + + return self::FAILURE; + } + +} diff --git a/Engine/Console/Commands/Example/ExampleBatchCallCommand.php b/Engine/Console/Commands/Example/BatchCallCommand.php similarity index 86% rename from Engine/Console/Commands/Example/ExampleBatchCallCommand.php rename to Engine/Console/Commands/Example/BatchCallCommand.php index 2a6eaad..34e74cd 100644 --- a/Engine/Console/Commands/Example/ExampleBatchCallCommand.php +++ b/Engine/Console/Commands/Example/BatchCallCommand.php @@ -9,7 +9,7 @@ * * @package Oforge\Engine\Console\Commands\Example */ -class ExampleBatchCallCommand extends AbstractBatchCallCommand { +class BatchCallCommand extends AbstractBatchCallCommand { /** @var string $defaultName */ protected static $defaultName = 'example:batch'; /** @var array $commands */ diff --git a/Engine/Console/Commands/Example/ExampleCommand1.php b/Engine/Console/Commands/Example/Command1.php similarity index 93% rename from Engine/Console/Commands/Example/ExampleCommand1.php rename to Engine/Console/Commands/Example/Command1.php index 929fc3d..b4a3cab 100644 --- a/Engine/Console/Commands/Example/ExampleCommand1.php +++ b/Engine/Console/Commands/Example/Command1.php @@ -11,7 +11,7 @@ * * @package Oforge\Engine\Console\Commands\Example */ -class ExampleCommand1 extends AbstractCommand { +class Command1 extends AbstractCommand { /** @var string[] $config */ protected $config = [ 'name' => 'example:cmd1', diff --git a/Engine/Console/Commands/Example/ExampleCommand2.php b/Engine/Console/Commands/Example/Command2.php similarity index 93% rename from Engine/Console/Commands/Example/ExampleCommand2.php rename to Engine/Console/Commands/Example/Command2.php index f5b1872..0ee1118 100644 --- a/Engine/Console/Commands/Example/ExampleCommand2.php +++ b/Engine/Console/Commands/Example/Command2.php @@ -11,7 +11,7 @@ * * @package Oforge\Engine\Console\Commands\Example */ -class ExampleCommand2 extends AbstractCommand { +class Command2 extends AbstractCommand { /** @var string[] $config */ protected $config = [ 'name' => 'example:cmd2', diff --git a/Engine/Console/Commands/Example/ExampleCommand3.php b/Engine/Console/Commands/Example/Command3.php similarity index 93% rename from Engine/Console/Commands/Example/ExampleCommand3.php rename to Engine/Console/Commands/Example/Command3.php index 52fc230..7138abe 100644 --- a/Engine/Console/Commands/Example/ExampleCommand3.php +++ b/Engine/Console/Commands/Example/Command3.php @@ -11,7 +11,7 @@ * * @package Oforge\Engine\Console\Commands\Example */ -class ExampleCommand3 extends AbstractCommand { +class Command3 extends AbstractCommand { /** @var string[] $config */ protected $config = [ 'name' => 'example:cmd3', diff --git a/Engine/Console/Commands/Example/ExampleNamespaceCallCommand.php b/Engine/Console/Commands/Example/NamespaceCallCommand.php similarity index 67% rename from Engine/Console/Commands/Example/ExampleNamespaceCallCommand.php rename to Engine/Console/Commands/Example/NamespaceCallCommand.php index 891d371..935d584 100644 --- a/Engine/Console/Commands/Example/ExampleNamespaceCallCommand.php +++ b/Engine/Console/Commands/Example/NamespaceCallCommand.php @@ -9,9 +9,9 @@ * * @package Oforge\Engine\Console\Commands\Example */ -class ExampleNamespaceCallCommand extends AbstractNamespaceCallCommand { +class NamespaceCallCommand extends AbstractNamespaceCallCommand { /** @var string $namespace */ - protected $namespace = 'example'; // use namespace as defaultName if defaultName is not set. + protected $namespace = 'example:all'; // use namespace as defaultName if defaultName is not set. /** @var string[] $excludeCommands */ protected $excludeCommands = ['example:batch']; diff --git a/Engine/Console/Commands/Core/PingCommand.php b/Engine/Console/Commands/Oforge/PingCommand.php similarity index 94% rename from Engine/Console/Commands/Core/PingCommand.php rename to Engine/Console/Commands/Oforge/PingCommand.php index 2a9b4a6..5917ee6 100644 --- a/Engine/Console/Commands/Core/PingCommand.php +++ b/Engine/Console/Commands/Oforge/PingCommand.php @@ -1,6 +1,6 @@ 'oforge:events:process-async', + 'name' => 'oforge:processAsyncEvents', 'description' => 'Async events processing', - 'hidden' => true, ]; /** @inheritdoc */ protected function execute(InputInterface $input, OutputInterface $output) { - $output->writeln('Start async event processing'); + $output->writeln('Start async event processing', OutputInterface::VERBOSITY_DEBUG); Oforge()->Events()->processAsyncEvents(); - $output->writeln('Finished'); + $output->writeln('Finished', OutputInterface::VERBOSITY_DEBUG); return self::SUCCESS; } diff --git a/Engine/Console/Commands/Oforge/ServiceCommand.php b/Engine/Console/Commands/Oforge/ServiceCommand.php new file mode 100644 index 0000000..3e1696b --- /dev/null +++ b/Engine/Console/Commands/Oforge/ServiceCommand.php @@ -0,0 +1,131 @@ + 'oforge:service', + 'description' => 'Caller for oforge service methods', + 'hidden' => true, + 'arguments' => [ + 'ServiceMethod' => [ + 'description' => 'Callable of service method (Format: :)', + 'default' => '', + ], + 'ServiceMethodArgument' => [ + 'mode' => InputArgument::OPTIONAL | InputArgument::IS_ARRAY, + 'description' => 'Argument(s) for service method', + 'default' => [], + ], + ], + ]; + + /** @inheritdoc */ + protected function execute(InputInterface $input, OutputInterface $output) { + $serviceMethod = $input->getArgument('ServiceMethod'); + if (empty($serviceMethod)) { + $this->renderList($output, ''); + } else { + $serviceArgs = $input->getArgument('ServiceMethodArgument'); + $this->callServiceMethod($output, $serviceMethod, $serviceArgs); + } + + return self::SUCCESS; + } + + /** + * @param OutputInterface $output + * @param string $call + * @param array $serviceArgs + */ + private function callServiceMethod(OutputInterface $output, string $call, array $serviceArgs) { + $parts = explode(':', $call); + $serviceName = $parts[0] ?? ''; + $serviceMethod = $parts[1] ?? null; + try { + $service = Oforge()->Services()->get($serviceName); + if ($serviceMethod === null || !method_exists($service, $serviceMethod)) { + $this->renderList($output, $serviceName); + } else { + $callable = [$service, $serviceMethod]; + $return = call_user_func_array($callable, $serviceArgs); + if (!empty($return) || is_numeric($return)) { + $output->writeln(is_scalar($return) ? $return : print_r($return, true)); + } + } + + } catch (Exception $exception) { + $this->renderList($output, ''); + } + } + + /** + * @param OutputInterface $output + * @param string $prefix + */ + private function renderList(OutputInterface $output, string $prefix) { + $serviceManager = Oforge()->Services(); + $serviceNames = $serviceManager->getServiceNames(); + sort($serviceNames); + $table = new Table($output); + $table->setHeaders(['Service method', 'Description']); + foreach ($serviceNames as $index => $serviceName) { + if ($index > 0 && $prefix === '') { + $table->addRow(new TableSeparator()); + } + try { + $service = $serviceManager->get($serviceName); + $serviceMethods = get_class_methods($service); + foreach ($serviceMethods as $serviceMethod) { + if (StringHelper::startsWith($serviceMethod, '__')) { + continue; + } + $call = $serviceName . ':' . $serviceMethod; + if (!($prefix === '' || StringHelper::startsWith($call, $prefix))) { + continue; + } + $row = [$call]; + $doc = '-'; + try { + $reflector = new \ReflectionClass($service); + $commentLines = explode("\n", $reflector->getMethod($serviceMethod)->getDocComment()); + if (count($commentLines) > 1) { + if (!StringHelper::contains($commentLines[1], '@param') + && !StringHelper::contains($commentLines[1], '@throws') + && !StringHelper::contains($commentLines[1], '@return')) { + $doc = strtr($commentLines[1], [ + '*' => '', + "\n" => '', + ]); + } + } + } catch (ReflectionException $exception) { + } + $row[] = trim($doc); + + $table->addRow($row); + } + } catch (ServiceNotFoundException $exception) { + } + } + $table->render(); + } + +} From c8ddcdb184c795528e8ceb3a55e8e36dd0f3e23f Mon Sep 17 00:00:00 2001 From: FK Date: Thu, 29 Oct 2020 15:49:49 +0100 Subject: [PATCH 06/11] Implementation of config validations --- .../Abstracts/AbstractBatchCallCommand.php | 15 +++++++++++---- .../Abstracts/AbstractNamespaceCallCommand.php | 5 +++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Engine/Console/Abstracts/AbstractBatchCallCommand.php b/Engine/Console/Abstracts/AbstractBatchCallCommand.php index c7da8f2..248aa8c 100644 --- a/Engine/Console/Abstracts/AbstractBatchCallCommand.php +++ b/Engine/Console/Abstracts/AbstractBatchCallCommand.php @@ -3,6 +3,7 @@ namespace Oforge\Engine\Console\Abstracts; use Exception; +use RuntimeException; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -64,6 +65,9 @@ protected function execute(InputInterface $input, OutputInterface $output) : int if ($this->getName() === $name) { continue; } + if (is_string($args) && method_exists($this, $args)) { + $args = $this->$args(); + } $errorCode = $this->callOtherCommand($output, $name, $args); if ($errorCode === self::FAILURE && $stopOnError) { return self::FAILURE; @@ -75,10 +79,10 @@ protected function execute(InputInterface $input, OutputInterface $output) : int private function checkBatchCallConfig() { if (!isset($this->commands)) { - //TODO + throw new RuntimeException("Property 'commands' not defined."); } if (empty($this->commands)) { - //TODO + throw new RuntimeException("Property 'commands' is empty."); } foreach ($this->commands as $name => $args) { if (!is_string($name)) { @@ -86,10 +90,13 @@ private function checkBatchCallConfig() { $args = []; } if (!is_string($name)) { - //TODO + throw new RuntimeException("Command name '$name' is not a string."); + } + if ($args === null) { + throw new RuntimeException("Arguments of command '$name' is null."); } if (!(is_string($args) || is_array($args))) { - //TODO + throw new RuntimeException("Arguments of command '$name' is not a string or array."); } } } diff --git a/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php b/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php index 288ea0a..de41dfc 100644 --- a/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php +++ b/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php @@ -3,6 +3,7 @@ namespace Oforge\Engine\Console\Abstracts; use Exception; +use RuntimeException; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -44,7 +45,7 @@ public function __construct(string $namespace = null, array $excludeCommands = [ /** @inheritdoc */ protected function configure() { $this->addOption(self::OPTION_STOP_ON_ERROR, null, InputOption::VALUE_NONE, 'Quit when a subcommand fails.'); - $this->setDescription('Call all commands of namespace: "' . $this->namespace . '"'); + $this->setDescription("Call all commands of namespace: '{$this->namespace}'"); parent::configure(); } @@ -75,7 +76,7 @@ protected function execute(InputInterface $input, OutputInterface $output) : int private function checNamespaceCallConfig() { if (empty($this->namespace)) { - //TODO + throw new RuntimeException("Property 'namespace' not defined."); } } } From 3500418ecd9252fceb367509b54739d5fdbc2ce2 Mon Sep 17 00:00:00 2001 From: FK Date: Sat, 31 Oct 2020 18:05:25 +0100 Subject: [PATCH 07/11] Implement logger connection --- Engine/Console/Abstracts/AbstractCommand.php | 47 +++-- Engine/Console/Lib/ConsoleFormatter.php | 25 +++ .../Lib/MonologBridge/ConsoleHandler.php | 161 ++++++++++++++++++ 3 files changed, 222 insertions(+), 11 deletions(-) create mode 100644 Engine/Console/Lib/ConsoleFormatter.php create mode 100644 Engine/Console/Lib/MonologBridge/ConsoleHandler.php diff --git a/Engine/Console/Abstracts/AbstractCommand.php b/Engine/Console/Abstracts/AbstractCommand.php index 2401634..e11fb18 100644 --- a/Engine/Console/Abstracts/AbstractCommand.php +++ b/Engine/Console/Abstracts/AbstractCommand.php @@ -3,6 +3,12 @@ namespace Oforge\Engine\Console\Abstracts; use Exception; +use Monolog\Logger; +use Oforge\Engine\Console\Lib\ConsoleFormatter; +use Oforge\Engine\Console\Lib\MonologBridge\ConsoleHandler; +use Oforge\Engine\Core\Exceptions\LoggerAlreadyExistException; +use Oforge\Engine\Core\Helper\Statics; +use Oforge\Engine\Core\Manager\Logger\LoggerManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputArgument; @@ -46,6 +52,7 @@ abstract class AbstractCommand extends Command { * @var array $config */ protected $config = []; + /** @var Logger|null $logger */ private $logger = null; /** @inheritdoc */ @@ -117,16 +124,34 @@ protected function callOtherCommand(OutputInterface $output, string $name, $args return $command->run($args, $output); } - // protected function getLogger(OutputInterface $output) { //not working yet, TODO howto combine of $output & logger - // if ($this->logger === null) { - // // $consoleLogger = new ConsoleLogger($output); - // // - // // $consoleLogger-> - // // - // // $this->logger = $consoleLogger; - // } - // - // return $this->logger; - // } + /** + * @param OutputInterface $output + * + * @return Logger|null + */ + protected function getLogger(OutputInterface $output) { + if ($this->logger === null) { + $consoleFormatter = new ConsoleFormatter(); + try { + $logger = Oforge()->Logger()->initLogger('Console:' . $this->getName(), [ + 'path' => implode(Statics::GLOBAL_SEPARATOR, [ + ROOT_PATH . Statics::DIR_LOG, + 'command', + str_replace(':', '.', $this->getName()) . LoggerManager::FILE_EXTENSION, + ]), + ]); + foreach ($logger->getHandlers() as $handler) { + $handler->setFormatter($consoleFormatter); + } + } catch (LoggerAlreadyExistException $exception) { + $logger = Oforge()->Logger()->get('Console:' . $this->getName()); + } + $consoleHandler = new ConsoleHandler($output); + $logger->pushHandler($consoleHandler->setFormatter($consoleFormatter)); + $this->logger = $logger; + } + + return $this->logger; + } } diff --git a/Engine/Console/Lib/ConsoleFormatter.php b/Engine/Console/Lib/ConsoleFormatter.php new file mode 100644 index 0000000..79202d2 --- /dev/null +++ b/Engine/Console/Lib/ConsoleFormatter.php @@ -0,0 +1,25 @@ +ignoreEmptyContextAndExtra = true; + $this->includeStacktraces = true; + } + +} diff --git a/Engine/Console/Lib/MonologBridge/ConsoleHandler.php b/Engine/Console/Lib/MonologBridge/ConsoleHandler.php new file mode 100644 index 0000000..3ee4db4 --- /dev/null +++ b/Engine/Console/Lib/MonologBridge/ConsoleHandler.php @@ -0,0 +1,161 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Oforge\Engine\Console\Lib\MonologBridge; + +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; +use Monolog\Handler\AbstractProcessingHandler; +use Monolog\Logger; +use Symfony\Component\Console\ConsoleEvents; +use Symfony\Component\Console\Event\ConsoleCommandEvent; +use Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Symfony\Component\Console\Output\ConsoleOutputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Writes logs to the console output depending on its verbosity setting. + * It is disabled by default and gets activated as soon as a command is executed. + * Instead of listening to the console events, the output can also be set manually. + * The minimum logging level at which this handler will be triggered depends on the + * verbosity setting of the console output. The default mapping is: + * - OutputInterface::VERBOSITY_NORMAL will show all WARNING and higher logs + * - OutputInterface::VERBOSITY_VERBOSE (-v) will show all NOTICE and higher logs + * - OutputInterface::VERBOSITY_VERY_VERBOSE (-vv) will show all INFO and higher logs + * - OutputInterface::VERBOSITY_DEBUG (-vvv) will show all DEBUG and higher logs, i.e. all logs + * This mapping can be customized with the $verbosityLevelMap constructor parameter. + * + * @author Tobias Schultze + */ +class ConsoleHandler extends AbstractProcessingHandler { + /** @var OutputInterface|null $output */ + private $output; + /** @var array $verbosityLevelMap */ + private $verbosityLevelMap = [ + OutputInterface::VERBOSITY_QUIET => Logger::ERROR, + OutputInterface::VERBOSITY_NORMAL => Logger::WARNING, + OutputInterface::VERBOSITY_VERBOSE => Logger::NOTICE, + OutputInterface::VERBOSITY_VERY_VERBOSE => Logger::INFO, + OutputInterface::VERBOSITY_DEBUG => Logger::DEBUG, + ]; + + /** + * @param OutputInterface $output The console output to use (the handler remains disabled when passing null + * until the output is set, e.g. by using console events) + * @param bool $bubble Whether the messages that are handled can bubble up the stack + * @param array $verbosityLevelMap Array that maps the OutputInterface verbosity to a minimum logging + * level (leave empty to use the default mapping) + */ + public function __construct(OutputInterface $output, bool $bubble = true, array $verbosityLevelMap = []) { + parent::__construct(Logger::DEBUG, $bubble); + $this->output = $output; + if (!empty($verbosityLevelMap)) { + $this->verbosityLevelMap = $verbosityLevelMap; + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + return [ + ConsoleEvents::COMMAND => ['onCommand', 255], + ConsoleEvents::TERMINATE => ['onTerminate', -255], + ]; + } + + /** + * {@inheritdoc} + */ + public function isHandling(array $record) : bool { + return $this->updateLevel() && parent::isHandling($record); + } + + /** + * {@inheritdoc} + */ + public function handle(array $record) : bool { + // we have to update the logging level each time because the verbosity of the + // console output might have changed in the meantime (it is not immutable) + return $this->updateLevel() && parent::handle($record); + } + + /** + * Sets the console output to use for printing logs. + */ + public function setOutput(OutputInterface $output) { + $this->output = $output; + } + + /** + * Disables the output. + */ + public function close() : void { + $this->output = null; + + parent::close(); + } + + /** + * Before a command is executed, the handler gets activated and the console output + * is set in order to know where to write the logs. + */ + public function onCommand(ConsoleCommandEvent $event) { + $output = $event->getOutput(); + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + + $this->setOutput($output); + } + + /** + * After a command has been executed, it disables the output. + */ + public function onTerminate(ConsoleTerminateEvent $event) { + $this->close(); + } + + /** + * {@inheritdoc} + */ + protected function write(array $record) : void { + // at this point we've determined for sure that we want to output the record, so use the output's own verbosity + $this->output->write((string) $record['formatted'], false, $this->output->getVerbosity()); + } + + /** + * {@inheritdoc} + */ + protected function getDefaultFormatter() : FormatterInterface { + return new LineFormatter(); + } + + /** + * Updates the logging level based on the verbosity setting of the console output. + * + * @return bool Whether the handler is enabled and verbosity is not set to quiet + */ + private function updateLevel() : bool { + if (null === $this->output) { + return false; + } + + $verbosity = $this->output->getVerbosity(); + if (isset($this->verbosityLevelMap[$verbosity])) { + $this->setLevel($this->verbosityLevelMap[$verbosity]); + } else { + $this->setLevel(Logger::DEBUG); + } + + return true; + } +} From bd78060b707d7072ea9f7cfac87b153bde3d87d0 Mon Sep 17 00:00:00 2001 From: FK Date: Sat, 31 Oct 2020 19:29:18 +0100 Subject: [PATCH 08/11] Make Bootstrap singletons --- Engine/Auth/Bootstrap.php | 3 +- Engine/Console/Bootstrap.php | 3 +- Engine/Core/Abstracts/AbstractBootstrap.php | 11 ++++ .../Manager/Bootstrap/BootstrapManager.php | 65 +++++++------------ Engine/Core/Traits/SingletonTrait.php | 28 ++++++++ Engine/Crud/Bootstrap.php | 3 +- Engine/File/Bootstrap.php | 3 +- Engine/Image/Bootstrap.php | 3 +- 8 files changed, 73 insertions(+), 46 deletions(-) create mode 100644 Engine/Core/Traits/SingletonTrait.php diff --git a/Engine/Auth/Bootstrap.php b/Engine/Auth/Bootstrap.php index 85a3024..5d139bf 100644 --- a/Engine/Auth/Bootstrap.php +++ b/Engine/Auth/Bootstrap.php @@ -22,7 +22,8 @@ class Bootstrap extends AbstractBootstrap { /** * Bootstrap constructor. */ - public function __construct() { + protected function __construct() { + parent::__construct(); $this->models = [ User::class, ]; diff --git a/Engine/Console/Bootstrap.php b/Engine/Console/Bootstrap.php index 78296ab..7a1778d 100644 --- a/Engine/Console/Bootstrap.php +++ b/Engine/Console/Bootstrap.php @@ -16,7 +16,8 @@ class Bootstrap extends AbstractBootstrap { /** * Console-Bootstrap constructor. */ - public function __construct() { + protected function __construct() { + parent::__construct(); $this->setConfiguration('commands', [ Commands\Oforge\PingCommand::class, Commands\Oforge\ProcessAsyncEventsCommand::class, diff --git a/Engine/Core/Abstracts/AbstractBootstrap.php b/Engine/Core/Abstracts/AbstractBootstrap.php index cdffe21..4a195b1 100644 --- a/Engine/Core/Abstracts/AbstractBootstrap.php +++ b/Engine/Core/Abstracts/AbstractBootstrap.php @@ -4,6 +4,7 @@ use Exception; use Oforge\Engine\Core\Helper\Statics; +use Oforge\Engine\Core\Traits\SingletonTrait; /** * Class AbstractBootstrap @@ -12,6 +13,10 @@ * @package Oforge\Engine\Core\Abstracts */ abstract class AbstractBootstrap { + use SingletonTrait; + + /** @var static $instance */ + protected static $instance = null; /** * @var string[] $cronjobs */ @@ -43,6 +48,12 @@ abstract class AbstractBootstrap { /** @var array $configuration */ private $configuration = []; + /** + * AbstractBootstrap constructor. + */ + protected function __construct() { + } + /** @throws Exception */ public function install() { } diff --git a/Engine/Core/Manager/Bootstrap/BootstrapManager.php b/Engine/Core/Manager/Bootstrap/BootstrapManager.php index 13c3f2f..630e606 100644 --- a/Engine/Core/Manager/Bootstrap/BootstrapManager.php +++ b/Engine/Core/Manager/Bootstrap/BootstrapManager.php @@ -8,18 +8,16 @@ use Oforge\Engine\Core\Helper\FileSystemHelper; use Oforge\Engine\Core\Helper\Statics; use Oforge\Engine\Core\Helper\StringHelper; -use Oforge\Engine\TemplateEngine\Core\Abstracts\AbstractTemplate; /** * Class BootstrapManager * * @package Oforge\Engine\Core\Manager\BootstrapManager */ -class BootstrapManager -{ +class BootstrapManager { private const FILE_PATH = ROOT_PATH . Statics::DIR_CACHE . Statics::GLOBAL_SEPARATOR . 'bootstrap.cache.php'; - public const KEY_PATH = 'path'; - public const KEY_NS = 'namespace'; + public const KEY_PATH = 'path'; + public const KEY_NS = 'namespace'; /** @var BootstrapManager $instance */ protected static $instance = null; /** @var array $bootstrapData */ @@ -27,15 +25,13 @@ class BootstrapManager /** @var array $bootstrapInstances s */ private $bootstrapInstances = []; - protected function __construct() - { + protected function __construct() { } /** * @return BootstrapManager */ - public static function getInstance(): BootstrapManager - { + public static function getInstance() : BootstrapManager { if (is_null(self::$instance)) { self::$instance = new BootstrapManager(); } @@ -48,8 +44,7 @@ public static function getInstance(): BootstrapManager * * @return AbstractBootstrap|null */ - public function getBootstrapInstance(string $class): ?AbstractBootstrap - { + public function getBootstrapInstance(string $class) : ?AbstractBootstrap { if (isset($this->bootstrapInstances[$class])) { return $this->bootstrapInstances[$class]; } @@ -62,8 +57,7 @@ public function getBootstrapInstance(string $class): ?AbstractBootstrap * * @return array */ - public function getBootstrapInstances(): array - { + public function getBootstrapInstances() : array { return $this->bootstrapInstances; } @@ -72,8 +66,7 @@ public function getBootstrapInstances(): array * * @return mixed */ - public function getModuleBootstrapData() - { + public function getModuleBootstrapData() { return $this->bootstrapData[Statics::ENGINE_DIR]; } @@ -82,17 +75,14 @@ public function getModuleBootstrapData() * * @return mixed */ - public function getPluginBootstrapData() - { + public function getPluginBootstrapData() { return $this->bootstrapData[Statics::PLUGIN_DIR]; } - /** * Initialize all modules and plugins bootstrap data. */ - public function init() - { + public function init() { $isDevelopmentMode = Oforge()->Settings()->isDevelopmentMode(); if ($isDevelopmentMode) { $this->collectBootstrapData(); @@ -119,16 +109,15 @@ public function init() foreach ($this->bootstrapData as $type => $data) { foreach ($data as $bootstrapClass => $bootstrapData) { if (is_subclass_of($bootstrapClass, AbstractBootstrap::class)) { + echo "1: "; + var_dump($bootstrapClass); + $instance = $bootstrapClass::getInstance(); /** @var AbstractBootstrap $instance */ - $instance = new $bootstrapClass(); if ($bootstrapClass === CoreBootstrap::class) { Oforge()->DB()->initModelSchema($instance->getModels()); } - $this->bootstrapInstances[$bootstrapClass] = $instance; - } elseif (is_subclass_of($bootstrapClass, AbstractTemplate::class)) { - /** @var AbstractTemplate $instance */ - $instance = new $bootstrapClass(); - + echo "3: "; + var_dump(get_class($instance)); $this->bootstrapInstances[$bootstrapClass] = $instance; } } @@ -138,8 +127,7 @@ public function init() /** * Create parent folder if not exist and updates Bootstrap-data file. */ - public function updateBootstrapData() - { + public function updateBootstrapData() { $this->collectBootstrapData(); if (!file_exists($dir = dirname(self::FILE_PATH))) { @@ -154,8 +142,7 @@ public function updateBootstrapData() /** * Collect and set all Bootstrap-data of modules and plugins. */ - protected function collectBootstrapData() - { + protected function collectBootstrapData() { $bootstrapData = [ Statics::ENGINE_DIR => $this->collectBootstrapDataSub(Statics::ENGINE_DIR), Statics::PLUGIN_DIR => $this->collectBootstrapDataSub(Statics::PLUGIN_DIR), @@ -171,26 +158,22 @@ protected function collectBootstrapData() * * @return array */ - protected function collectBootstrapDataSub(string $context) - { + protected function collectBootstrapDataSub(string $context) { $isModule = $context === Statics::ENGINE_DIR; - $isPlugin = $context === Statics::PLUGIN_DIR; - $data = []; - $files = FileSystemHelper::getBootstrapFiles(ROOT_PATH . Statics::GLOBAL_SEPARATOR . $context); + $data = []; + $files = FileSystemHelper::getBootstrapFiles(ROOT_PATH . Statics::GLOBAL_SEPARATOR . $context); foreach ($files as $file) { $directory = dirname($file); $class = str_replace('/', '\\', str_replace(ROOT_PATH, '', $directory)) . '\Bootstrap'; - $class = 'Oforge'.$class; + $class = 'Oforge' . $class; - if ($isModule || $isPlugin) { - $namespace = StringHelper::rightTrim($class, '\\Bootstrap'); - } - $class = StringHelper::leftTrim($class, '\\'); + $namespace = StringHelper::rightTrim($class, '\\Bootstrap'); + $class = StringHelper::leftTrim($class, '\\'); $data[$class] = [ - self::KEY_NS => $namespace, + self::KEY_NS => $namespace, self::KEY_PATH => $directory, ]; } diff --git a/Engine/Core/Traits/SingletonTrait.php b/Engine/Core/Traits/SingletonTrait.php new file mode 100644 index 0000000..32e833a --- /dev/null +++ b/Engine/Core/Traits/SingletonTrait.php @@ -0,0 +1,28 @@ +Logger()->initLogger('crud'); } catch (LoggerAlreadyExistException $exception) { diff --git a/Engine/File/Bootstrap.php b/Engine/File/Bootstrap.php index 7bf82f7..5e817c3 100644 --- a/Engine/File/Bootstrap.php +++ b/Engine/File/Bootstrap.php @@ -14,7 +14,8 @@ class Bootstrap extends AbstractBootstrap { /** Bootstrap constructor. */ - public function __construct() { + protected function __construct() { + parent::__construct(); // $this->endpoints = [ // Controllers\Api\FileController::class, // ]; diff --git a/Engine/Image/Bootstrap.php b/Engine/Image/Bootstrap.php index b017bd3..1be4e28 100644 --- a/Engine/Image/Bootstrap.php +++ b/Engine/Image/Bootstrap.php @@ -16,7 +16,8 @@ class Bootstrap extends AbstractBootstrap { /** Bootstrap constructor. */ - public function __construct() { + protected function __construct() { + parent::__construct(); try { Oforge()->Logger()->initLogger(Enums\ImageConstants::LOGGER); } catch (LoggerAlreadyExistException $exception) { From afc334e513bde306a94979779d42f16e5cf92862 Mon Sep 17 00:00:00 2001 From: FK Date: Sat, 31 Oct 2020 19:30:10 +0100 Subject: [PATCH 09/11] Remove forgotten debug logs --- Engine/Core/Manager/Bootstrap/BootstrapManager.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Engine/Core/Manager/Bootstrap/BootstrapManager.php b/Engine/Core/Manager/Bootstrap/BootstrapManager.php index 630e606..8ff9d90 100644 --- a/Engine/Core/Manager/Bootstrap/BootstrapManager.php +++ b/Engine/Core/Manager/Bootstrap/BootstrapManager.php @@ -109,15 +109,11 @@ public function init() { foreach ($this->bootstrapData as $type => $data) { foreach ($data as $bootstrapClass => $bootstrapData) { if (is_subclass_of($bootstrapClass, AbstractBootstrap::class)) { - echo "1: "; - var_dump($bootstrapClass); - $instance = $bootstrapClass::getInstance(); /** @var AbstractBootstrap $instance */ + $instance = $bootstrapClass::getInstance(); if ($bootstrapClass === CoreBootstrap::class) { Oforge()->DB()->initModelSchema($instance->getModels()); } - echo "3: "; - var_dump(get_class($instance)); $this->bootstrapInstances[$bootstrapClass] = $instance; } } From 43cefa7640411e61aa34ce3787e8da6a17ed29a7 Mon Sep 17 00:00:00 2001 From: FK Date: Sun, 1 Nov 2020 15:33:37 +0100 Subject: [PATCH 10/11] Console cleanups & phpdocs, Singletons Traits --- .../Abstracts/AbstractBatchCallCommand.php | 7 +++++ .../AbstractNamespaceCallCommand.php | 14 ++++++++-- Engine/Console/Bootstrap.php | 3 +- .../Cleanup/Cache/DoctrineProxyCommand.php | 2 +- .../Cleanup/Cache/NamespaceCallCommand.php | 2 +- .../Commands/Cleanup/LogFilesCommand.php | 1 + .../Dev/Cleanup/Cache/DoctrineCommand.php | 2 +- .../Console/Commands/Oforge/PingCommand.php | 2 +- .../Oforge/ProcessAsyncEventsCommand.php | 3 +- .../Commands/Oforge/ServiceCommand.php | 2 +- .../Lib/MonologBridge/ConsoleHandler.php | 2 +- Engine/Console/Managers/ConsoleManager.php | 5 ++-- Engine/Core/Abstracts/AbstractBootstrap.php | 4 +-- .../Manager/Bootstrap/BootstrapManager.php | 22 ++++----------- .../Traits/AbstractClassSingletonTrait.php | 28 +++++++++++++++++++ Engine/Core/Traits/SingletonTrait.php | 10 +++---- 16 files changed, 72 insertions(+), 37 deletions(-) create mode 100644 Engine/Core/Traits/AbstractClassSingletonTrait.php diff --git a/Engine/Console/Abstracts/AbstractBatchCallCommand.php b/Engine/Console/Abstracts/AbstractBatchCallCommand.php index 248aa8c..82ee9f3 100644 --- a/Engine/Console/Abstracts/AbstractBatchCallCommand.php +++ b/Engine/Console/Abstracts/AbstractBatchCallCommand.php @@ -37,6 +37,7 @@ abstract class AbstractBatchCallCommand extends AbstractCommand { * * @param string|null $name * @param array $commands + * @throws RuntimeException */ public function __construct(string $name = null, array $commands = []) { $this->commands = $this->commands ?? $commands; @@ -52,6 +53,7 @@ protected function configure() { /** * @inheritDoc + * @throws RuntimeException * @throws Exception */ protected function execute(InputInterface $input, OutputInterface $output) : int { @@ -77,6 +79,11 @@ protected function execute(InputInterface $input, OutputInterface $output) : int return self::SUCCESS; } + /** + * Validate command config + * + * @throws RuntimeException + */ private function checkBatchCallConfig() { if (!isset($this->commands)) { throw new RuntimeException("Property 'commands' not defined."); diff --git a/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php b/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php index de41dfc..a47989e 100644 --- a/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php +++ b/Engine/Console/Abstracts/AbstractNamespaceCallCommand.php @@ -34,11 +34,12 @@ abstract class AbstractNamespaceCallCommand extends AbstractCommand { * * @param string|null $namespace * @param array $excludeCommands + * @throws RuntimeException */ public function __construct(string $namespace = null, array $excludeCommands = []) { $this->namespace = rtrim($this->namespace ?? trim($namespace), ':'); $this->excludeCommands = $this->excludeCommands ?? (empty($excludeCommands) ? null : $excludeCommands); - $this->checNamespaceCallConfig(); + $this->checkNamespaceCallConfig(); parent::__construct(static::$defaultName ?? $this->namespace); } @@ -51,10 +52,11 @@ protected function configure() { /** * @inheritDoc + * @throws RuntimeException * @throws Exception */ protected function execute(InputInterface $input, OutputInterface $output) : int { - $this->checNamespaceCallConfig(); + $this->checkNamespaceCallConfig(); $stopOnError = $input->getOption(self::OPTION_STOP_ON_ERROR); $commands = $this->getApplication()->all($this->namespace); if (!is_array($commands)) { @@ -74,9 +76,15 @@ protected function execute(InputInterface $input, OutputInterface $output) : int return self::SUCCESS; } - private function checNamespaceCallConfig() { + /** + * Validate command config + * + * @throws RuntimeException + */ + private function checkNamespaceCallConfig() { if (empty($this->namespace)) { throw new RuntimeException("Property 'namespace' not defined."); } } + } diff --git a/Engine/Console/Bootstrap.php b/Engine/Console/Bootstrap.php index 7a1778d..e27a993 100644 --- a/Engine/Console/Bootstrap.php +++ b/Engine/Console/Bootstrap.php @@ -34,7 +34,8 @@ protected function __construct() { Commands\Example\NamespaceCallCommand::class, ]); - Oforge()->Events()->attach('Oforge:Extension:init', Event::SYNC, function(Event $event) { + // TODO after core refactoring: attach only if extension active + Oforge()->Events()->attach('Oforge:Extension:init', Event::SYNC, function (Event $event) { /** @var AbstractBootstrap $boostrap */ $boostrap = $event->getDataValue('bootstrap'); ConsoleManager::registerCommandClasses($boostrap->getConfiguration('commands')); diff --git a/Engine/Console/Commands/Cleanup/Cache/DoctrineProxyCommand.php b/Engine/Console/Commands/Cleanup/Cache/DoctrineProxyCommand.php index 6de5079..f57236b 100644 --- a/Engine/Console/Commands/Cleanup/Cache/DoctrineProxyCommand.php +++ b/Engine/Console/Commands/Cleanup/Cache/DoctrineProxyCommand.php @@ -11,7 +11,7 @@ /** * Class DoctrineProxyCommand * - * @package Oforge\Engine\Console\Commands\Cleanup + * @package Oforge\Engine\Console\Commands\Cleanup\Cache */ class DoctrineProxyCommand extends AbstractCommand { /** @var string[] $config */ diff --git a/Engine/Console/Commands/Cleanup/Cache/NamespaceCallCommand.php b/Engine/Console/Commands/Cleanup/Cache/NamespaceCallCommand.php index ba657a6..f5cb367 100644 --- a/Engine/Console/Commands/Cleanup/Cache/NamespaceCallCommand.php +++ b/Engine/Console/Commands/Cleanup/Cache/NamespaceCallCommand.php @@ -7,7 +7,7 @@ /** * Class NamespaceCallCommand * - * @package Oforge\Engine\Console\Commands\Dev + * @package Oforge\Engine\Console\Commands\Cleanup\Cache */ class NamespaceCallCommand extends AbstractNamespaceCallCommand { /** @var string $namespace */ diff --git a/Engine/Console/Commands/Cleanup/LogFilesCommand.php b/Engine/Console/Commands/Cleanup/LogFilesCommand.php index 89830cc..038514f 100644 --- a/Engine/Console/Commands/Cleanup/LogFilesCommand.php +++ b/Engine/Console/Commands/Cleanup/LogFilesCommand.php @@ -39,4 +39,5 @@ protected function execute(InputInterface $input, OutputInterface $output) { return self::SUCCESS; } + } diff --git a/Engine/Console/Commands/Dev/Cleanup/Cache/DoctrineCommand.php b/Engine/Console/Commands/Dev/Cleanup/Cache/DoctrineCommand.php index de95633..1f565c5 100644 --- a/Engine/Console/Commands/Dev/Cleanup/Cache/DoctrineCommand.php +++ b/Engine/Console/Commands/Dev/Cleanup/Cache/DoctrineCommand.php @@ -11,7 +11,7 @@ /** * Class DoctrineCommand * - * @package Oforge\Engine\Console\Commands\Dev\Cleanup + * @package Oforge\Engine\Console\Commands\Dev\Cleanup\Cache */ class DoctrineCommand extends AbstractCommand { /** @var string[] $config */ diff --git a/Engine/Console/Commands/Oforge/PingCommand.php b/Engine/Console/Commands/Oforge/PingCommand.php index 5917ee6..d45b412 100644 --- a/Engine/Console/Commands/Oforge/PingCommand.php +++ b/Engine/Console/Commands/Oforge/PingCommand.php @@ -10,7 +10,7 @@ /** * Class PingCommand * - * @package Oforge\Engine\Console\Commands\Core + * @package Oforge\Engine\Console\Commands\Oforge */ class PingCommand extends AbstractCommand { /** @var string[] $config */ diff --git a/Engine/Console/Commands/Oforge/ProcessAsyncEventsCommand.php b/Engine/Console/Commands/Oforge/ProcessAsyncEventsCommand.php index 9e20e58..6621a18 100644 --- a/Engine/Console/Commands/Oforge/ProcessAsyncEventsCommand.php +++ b/Engine/Console/Commands/Oforge/ProcessAsyncEventsCommand.php @@ -9,7 +9,7 @@ /** * Class ProcessAsyncEventsCommand * - * @package Oforge\Engine\Console\Commands\Core + * @package Oforge\Engine\Console\Commands\Oforge */ class ProcessAsyncEventsCommand extends AbstractCommand { /** @var array $config */ @@ -26,4 +26,5 @@ protected function execute(InputInterface $input, OutputInterface $output) { return self::SUCCESS; } + } diff --git a/Engine/Console/Commands/Oforge/ServiceCommand.php b/Engine/Console/Commands/Oforge/ServiceCommand.php index 3e1696b..eb2dffc 100644 --- a/Engine/Console/Commands/Oforge/ServiceCommand.php +++ b/Engine/Console/Commands/Oforge/ServiceCommand.php @@ -16,7 +16,7 @@ /** * Class ServiceCommand * - * @package Oforge\Engine\Console\Commands\Core + * @package Oforge\Engine\Console\Commands\Oforge */ class ServiceCommand extends AbstractCommand { /** @var array $config */ diff --git a/Engine/Console/Lib/MonologBridge/ConsoleHandler.php b/Engine/Console/Lib/MonologBridge/ConsoleHandler.php index 3ee4db4..b46c0b8 100644 --- a/Engine/Console/Lib/MonologBridge/ConsoleHandler.php +++ b/Engine/Console/Lib/MonologBridge/ConsoleHandler.php @@ -3,7 +3,7 @@ /* * This file is part of the Symfony package. * - * (c) Fabien Potencier + * (c) Fabien Potencier (oforge adjusted version) * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/Engine/Console/Managers/ConsoleManager.php b/Engine/Console/Managers/ConsoleManager.php index 8b988bb..0759720 100644 --- a/Engine/Console/Managers/ConsoleManager.php +++ b/Engine/Console/Managers/ConsoleManager.php @@ -2,6 +2,7 @@ namespace Oforge\Engine\Console\Managers; +use Exception; use Oforge\Engine\Core\Exceptions\InvalidClassException; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; @@ -65,7 +66,7 @@ public static function registerCommandClasses($commandClasses) { } /** - * @throws \Exception + * @throws Exception */ public function run() { $output = $this->application->run(null, $this->output); @@ -77,7 +78,7 @@ public function run() { * @param bool $consoleOutput * * @return int - * @throws \Exception + * @throws Exception */ public function callCommand(string $name, $args, bool $consoleOutput = true) { $command = $this->application->find($name); diff --git a/Engine/Core/Abstracts/AbstractBootstrap.php b/Engine/Core/Abstracts/AbstractBootstrap.php index 4a195b1..6f220fc 100644 --- a/Engine/Core/Abstracts/AbstractBootstrap.php +++ b/Engine/Core/Abstracts/AbstractBootstrap.php @@ -4,7 +4,7 @@ use Exception; use Oforge\Engine\Core\Helper\Statics; -use Oforge\Engine\Core\Traits\SingletonTrait; +use Oforge\Engine\Core\Traits\AbstractClassSingletonTrait; /** * Class AbstractBootstrap @@ -13,7 +13,7 @@ * @package Oforge\Engine\Core\Abstracts */ abstract class AbstractBootstrap { - use SingletonTrait; + use AbstractClassSingletonTrait; /** @var static $instance */ protected static $instance = null; diff --git a/Engine/Core/Manager/Bootstrap/BootstrapManager.php b/Engine/Core/Manager/Bootstrap/BootstrapManager.php index 8ff9d90..0bdc736 100644 --- a/Engine/Core/Manager/Bootstrap/BootstrapManager.php +++ b/Engine/Core/Manager/Bootstrap/BootstrapManager.php @@ -8,6 +8,7 @@ use Oforge\Engine\Core\Helper\FileSystemHelper; use Oforge\Engine\Core\Helper\Statics; use Oforge\Engine\Core\Helper\StringHelper; +use Oforge\Engine\Core\Traits\SingletonTrait; /** * Class BootstrapManager @@ -15,11 +16,11 @@ * @package Oforge\Engine\Core\Manager\BootstrapManager */ class BootstrapManager { + use SingletonTrait; + private const FILE_PATH = ROOT_PATH . Statics::DIR_CACHE . Statics::GLOBAL_SEPARATOR . 'bootstrap.cache.php'; public const KEY_PATH = 'path'; public const KEY_NS = 'namespace'; - /** @var BootstrapManager $instance */ - protected static $instance = null; /** @var array $bootstrapData */ private $bootstrapData = []; /** @var array $bootstrapInstances s */ @@ -28,17 +29,6 @@ class BootstrapManager { protected function __construct() { } - /** - * @return BootstrapManager - */ - public static function getInstance() : BootstrapManager { - if (is_null(self::$instance)) { - self::$instance = new BootstrapManager(); - } - - return self::$instance; - } - /** * @param string $class * @@ -161,9 +151,7 @@ protected function collectBootstrapDataSub(string $context) { foreach ($files as $file) { $directory = dirname($file); - $class = str_replace('/', '\\', str_replace(ROOT_PATH, '', $directory)) . '\Bootstrap'; - - $class = 'Oforge' . $class; + $class = 'Oforge' . str_replace('/', '\\', str_replace(ROOT_PATH, '', $directory)) . '\Bootstrap'; $namespace = StringHelper::rightTrim($class, '\\Bootstrap'); $class = StringHelper::leftTrim($class, '\\'); @@ -173,7 +161,7 @@ protected function collectBootstrapDataSub(string $context) { self::KEY_PATH => $directory, ]; } - if ($isModule) { + if ($isModule && isset($data[CoreBootstrap::class])) { // set CoreBootstrap as first entry $tmp = $data[CoreBootstrap::class]; unset($data[CoreBootstrap::class]); diff --git a/Engine/Core/Traits/AbstractClassSingletonTrait.php b/Engine/Core/Traits/AbstractClassSingletonTrait.php new file mode 100644 index 0000000..5cb3230 --- /dev/null +++ b/Engine/Core/Traits/AbstractClassSingletonTrait.php @@ -0,0 +1,28 @@ + $instance */ + private static $instances = []; + + /** + * Get or create and get singleton instance. + * + * @return static + */ + public static function getInstance() { + $class = get_called_class(); + if (!isset(self::$instances[$class])) { + self::$instances[$class] = new $class(); + } + + return self::$instances[$class]; + } + +} diff --git a/Engine/Core/Traits/SingletonTrait.php b/Engine/Core/Traits/SingletonTrait.php index 32e833a..eab73c0 100644 --- a/Engine/Core/Traits/SingletonTrait.php +++ b/Engine/Core/Traits/SingletonTrait.php @@ -3,13 +3,13 @@ namespace Oforge\Engine\Core\Traits; /** - * Trait SingletonTrait. + * Singleton trait classes. * * @package Oforge\Engine\Core\Traits */ trait SingletonTrait { /** @var static $instance */ - private static $instances = []; + private static $instance; /** * Get or create and get singleton instance. @@ -18,11 +18,11 @@ trait SingletonTrait { */ public static function getInstance() { $class = get_called_class(); - if (!isset(self::$instances[$class])) { - self::$instances[$class] = new $class(); + if (!isset(self::$instance)) { + self::$instance = new $class(); } - return self::$instances[$class]; + return self::$instance; } } From ee6bb8ddd79e49b7da1074d9aeffbf9f3cf47765 Mon Sep 17 00:00:00 2001 From: FK Date: Fri, 27 Nov 2020 21:35:43 +0100 Subject: [PATCH 11/11] Add (command) help print method + helper (for usage in input validation) --- Engine/Console/Abstracts/AbstractCommand.php | 17 ++++++++- Engine/Console/Helper/ConsoleHelper.php | 37 ++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 Engine/Console/Helper/ConsoleHelper.php diff --git a/Engine/Console/Abstracts/AbstractCommand.php b/Engine/Console/Abstracts/AbstractCommand.php index e11fb18..5db77d9 100644 --- a/Engine/Console/Abstracts/AbstractCommand.php +++ b/Engine/Console/Abstracts/AbstractCommand.php @@ -4,6 +4,7 @@ use Exception; use Monolog\Logger; +use Oforge\Engine\Console\Helper\ConsoleHelper; use Oforge\Engine\Console\Lib\ConsoleFormatter; use Oforge\Engine\Console\Lib\MonologBridge\ConsoleHandler; use Oforge\Engine\Core\Exceptions\LoggerAlreadyExistException; @@ -12,6 +13,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\OutputInterface; @@ -105,6 +107,19 @@ protected function configure() { } } + /** + * Printing command help. execute-Usage: + * return $this->printHelpForThisCommand($input, $output); + * + * @param InputInterface $input + * @param OutputInterface $output + * + * @return int + */ + protected function printHelpForThisCommand(InputInterface $input, OutputInterface $output) { + return ConsoleHelper::printCommandHelp($this, $input, $output); + } + /** * @param OutputInterface $output * @param string $name @@ -146,7 +161,7 @@ protected function getLogger(OutputInterface $output) { } catch (LoggerAlreadyExistException $exception) { $logger = Oforge()->Logger()->get('Console:' . $this->getName()); } - $consoleHandler = new ConsoleHandler($output); + $consoleHandler = new ConsoleHandler($output); $logger->pushHandler($consoleHandler->setFormatter($consoleFormatter)); $this->logger = $logger; } diff --git a/Engine/Console/Helper/ConsoleHelper.php b/Engine/Console/Helper/ConsoleHelper.php new file mode 100644 index 0000000..f4d7c90 --- /dev/null +++ b/Engine/Console/Helper/ConsoleHelper.php @@ -0,0 +1,37 @@ +setCommand($command); + + return $help->run($input, $output); + } + +}