From fa6ecced70948eacc0fdfe2369458e1feee538f1 Mon Sep 17 00:00:00 2001 From: alexecus Date: Thu, 5 Jul 2018 22:04:19 +0800 Subject: [PATCH 1/4] Added yaml operation --- src/App/Application.php | 1 + src/Definition/DefinitionArguments.php | 35 +++++++++++++++++++++ src/Definition/DefinitionCommand.php | 30 +++++++++++++----- src/Definition/DefinitionInputs.php | 3 +- src/Definition/DefinitionOperations.php | 30 ------------------ src/Operations/Yaml.php | 42 +++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 39 deletions(-) create mode 100644 src/Definition/DefinitionArguments.php create mode 100644 src/Operations/Yaml.php diff --git a/src/App/Application.php b/src/App/Application.php index 2eb49c1..cbce762 100644 --- a/src/App/Application.php +++ b/src/App/Application.php @@ -69,6 +69,7 @@ public function init() $this->addOperation('copy', Operations\Copy::class); $this->addOperation('notify', Operations\Notify::class); $this->addOperation('template', Operations\Template::class); + $this->addOperation('yaml', Operations\Yaml::class); $this->addValidator('empty', Validators\EmptyValidator::class); $this->addValidator('starts_with', Validators\StartsWithValidator::class); diff --git a/src/Definition/DefinitionArguments.php b/src/Definition/DefinitionArguments.php new file mode 100644 index 0000000..71584d1 --- /dev/null +++ b/src/Definition/DefinitionArguments.php @@ -0,0 +1,35 @@ + $value) { + $key = $this->resolveArguments($key, $vars); + + if (is_array($value)) { + $result[$key] = $this->resolveArguments($value, $vars); + } elseif (is_string($value)) { + $result[$key] = $this->doReplaceArguments($value, $vars); + } + } + + return $result; + } + + private function doReplaceArguments($value, $vars) + { + return preg_replace_callback('/\$\{(.*?)\}/', function ($matches) use ($vars) { + list($string, $match) = $matches; + + return isset($vars[$match]) ? $vars[$match] : $string; + }, $value); + } +} diff --git a/src/Definition/DefinitionCommand.php b/src/Definition/DefinitionCommand.php index 14b9e9c..861d19c 100644 --- a/src/Definition/DefinitionCommand.php +++ b/src/Definition/DefinitionCommand.php @@ -13,6 +13,7 @@ class DefinitionCommand extends Command { use DefinitionInputs; use DefinitionOperations; + use DefinitionArguments; private $root; private $yaml; @@ -40,21 +41,34 @@ public function execute(InputInterface $input, OutputInterface $output) $vars = []; $inputs = $this->yaml['inputs'] ?? []; - foreach ($inputs as $key => $input) { - if (isset($input['input'])) { - $action = $input['input']; + foreach ($inputs as $key => $options) { + if (isset($options['input'])) { + $action = $options['input']; + $options = $this->resolveArguments($options, $vars); - $vars[$key] = $this->handleInput($action, $input); + $vars[$key] = $this->handleInput($action, $options); } } $operations = $this->yaml['actions'] ?? []; - foreach ($operations as $key => $operation) { - if (isset($operation['action'])) { - $action = $operation['action']; + foreach ($operations as $key => $options) { + if (isset($options['action'])) { + $action = $options['action']; - $this->handleOperation($action, $operation, $vars); + $options = $this->resolveArguments($options, $vars); + + // Code for the IF directive + // don't execute an operation if an `if` condition is present + if (isset($options['if'])) { + $condition = $options['if']; + + if (isset($vars[$condition]) && !$vars[$condition]) { + continue; + } + } + + $this->handleOperation($action, $options, $vars); } } } diff --git a/src/Definition/DefinitionInputs.php b/src/Definition/DefinitionInputs.php index 1ca238c..60cbabc 100644 --- a/src/Definition/DefinitionInputs.php +++ b/src/Definition/DefinitionInputs.php @@ -34,9 +34,10 @@ public function handleInput($name, $options) $return = $instance->perform(...$arguments); // terminate directive + // if a terminate directive is present then stop script execution if (!empty($options['terminate']) && !$return) { exit; - } + } return $return; } diff --git a/src/Definition/DefinitionOperations.php b/src/Definition/DefinitionOperations.php index 45427e2..86f022d 100644 --- a/src/Definition/DefinitionOperations.php +++ b/src/Definition/DefinitionOperations.php @@ -15,18 +15,7 @@ public function handleOperation($name, $options, $vars) if ($instance) { $arguments = []; - // Code for the IF directive - if (isset($options['if'])) { - $condition = $options['if']; - - if (isset($vars[$condition]) && !$vars[$condition]) { - return; - } - } - $instance = $this->operation($name); - $options = $this->handleReplacements($options, $vars); - $params = (new ReflectionMethod($instance, 'perform'))->getParameters(); foreach ($params as $param) { @@ -52,23 +41,4 @@ public function handleOperation($name, $options, $vars) $instance->perform(...$arguments); } } - - private function handleReplacements($options, $vars) - { - $result = []; - - foreach ($options as $key => $value) { - if (is_array($value)) { - $result[$key] = $this->handleReplacements($value, $vars); - } elseif (is_string($value)) { - $result[$key] = preg_replace_callback('/\$\{(.*?)\}/', function ($matches) use ($vars) { - list($string, $match) = $matches; - - return isset($vars[$match]) ? $vars[$match] : $string; - }, $value); - } - } - - return $result; - } } diff --git a/src/Operations/Yaml.php b/src/Operations/Yaml.php new file mode 100644 index 0000000..684aa60 --- /dev/null +++ b/src/Operations/Yaml.php @@ -0,0 +1,42 @@ +filesystem = $filesystem; + } + + /** + * Performs the yaml operation + */ + public function perform(PathResource $target, array $append, $spaces = 2) + { + $data = []; + + try { + $data = Parser::parse($target->getAbsolute()); + } catch (ParseException $e) { + // handle invalid YAML scenario here + throw $e; + } + + $data = array_replace($data, $append); + $yaml = Yaml::dump($data, 2, $spaces); + + $this->filesystem->dumpFile($target->getAbsolute(), $yaml); + } +} From 38f21c86be5d09be674bd47584065e8d75c8b938 Mon Sep 17 00:00:00 2001 From: alexecus Date: Thu, 5 Jul 2018 22:32:54 +0800 Subject: [PATCH 2/4] Fixed fatal caused by file read issues --- src/Definition/DefinitionArguments.php | 2 +- src/Definition/DefinitionOperations.php | 5 +++-- src/Operations/Yaml.php | 18 +++++++++++++----- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Definition/DefinitionArguments.php b/src/Definition/DefinitionArguments.php index 71584d1..49318d9 100644 --- a/src/Definition/DefinitionArguments.php +++ b/src/Definition/DefinitionArguments.php @@ -12,7 +12,7 @@ private function resolveArguments($options, $vars) $result = []; foreach ($options as $key => $value) { - $key = $this->resolveArguments($key, $vars); + $key = $this->doReplaceArguments($key, $vars); if (is_array($value)) { $result[$key] = $this->resolveArguments($value, $vars); diff --git a/src/Definition/DefinitionOperations.php b/src/Definition/DefinitionOperations.php index 86f022d..172d808 100644 --- a/src/Definition/DefinitionOperations.php +++ b/src/Definition/DefinitionOperations.php @@ -2,10 +2,11 @@ namespace Alexecus\Spawner\Definition; -use Alexecus\Spawner\Resolver\PathResource; -use \ReflectionMethod; +use ReflectionMethod; use SebastianBergmann\CodeCoverage\RuntimeException; +use Alexecus\Spawner\Resolver\PathResource; + trait DefinitionOperations { public function handleOperation($name, $options, $vars) diff --git a/src/Operations/Yaml.php b/src/Operations/Yaml.php index 684aa60..a8a225d 100644 --- a/src/Operations/Yaml.php +++ b/src/Operations/Yaml.php @@ -2,11 +2,12 @@ namespace Alexecus\Spawner\Operations; -use Symfony\Component\Filesystem\Filesystem; +use Exception; use Symfony\Component\Yaml\Yaml as Parser; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Yaml\Exception\ParseException; use Alexecus\Spawner\Resolver\PathResource; -use Symfony\Component\Yaml\Exception\ParseException; class Yaml extends AbstractOperation { @@ -28,14 +29,21 @@ public function perform(PathResource $target, array $append, $spaces = 2) $data = []; try { - $data = Parser::parse($target->getAbsolute()); + $path = $target->getAbsolute(); + + if (file_exists($path)) { + $body = file_get_contents($path); + $data = Parser::parse($body); + } } catch (ParseException $e) { // handle invalid YAML scenario here throw $e; + } catch (Exception $e) { + // do nothing } - $data = array_replace($data, $append); - $yaml = Yaml::dump($data, 2, $spaces); + $data = array_replace_recursive($data, $append); + $yaml = Parser::dump($data, 2, $spaces); $this->filesystem->dumpFile($target->getAbsolute(), $yaml); } From c35428c856f46e3927b3dd98d00055fb9e0d8f04 Mon Sep 17 00:00:00 2001 From: alexecus Date: Sat, 7 Jul 2018 23:54:15 +0800 Subject: [PATCH 3/4] Added support for normalizers --- src/App/Application.php | 22 +++++++++ src/Command/Command.php | 1 + src/Command/CommandNormalizers.php | 29 ++++++++++++ src/Managers/NormalizerManager.php | 64 ++++++++++++++++++++++++++ src/Normalizers/AbstractNormalizer.php | 14 ++++++ src/Normalizers/SnakeCase.php | 16 +++++++ 6 files changed, 146 insertions(+) create mode 100644 src/Command/CommandNormalizers.php create mode 100644 src/Managers/NormalizerManager.php create mode 100644 src/Normalizers/AbstractNormalizer.php create mode 100644 src/Normalizers/SnakeCase.php diff --git a/src/App/Application.php b/src/App/Application.php index cbce762..d9c03b5 100644 --- a/src/App/Application.php +++ b/src/App/Application.php @@ -11,10 +11,12 @@ use Alexecus\Spawner\Managers\OperationsManager; use Alexecus\Spawner\Managers\ValidatorsManager; use Alexecus\Spawner\Managers\InputsManager; +use Alexecus\Spawner\Managers\NormalizerManager; use Alexecus\Spawner\Operations; use Alexecus\Spawner\Validators; use Alexecus\Spawner\Input; +use Alexecus\Spawner\Normalizers; /** * Class that bootstraps the generator application @@ -36,6 +38,11 @@ class Application */ private $inputs; + /** + * @var NormalizerManager + */ + private $normalizers; + /** * Stores the command * @@ -53,6 +60,7 @@ public function __construct($name = 'Spawner', $version = '1.0') $this->operations = Container::resolve(OperationsManager::class); $this->validators = Container::resolve(ValidatorsManager::class); $this->inputs = Container::resolve(InputsManager::class); + $this->normalizers = Container::resolve(NormalizerManager::class); $this->init(); } @@ -77,6 +85,8 @@ public function init() $this->addInput('ask', Input\AskInput::class); $this->addInput('confirm', Input\ConfirmInput::class); + + $this->addNormalizer('snake_case', Normalizers\SnakeCase::class); } /** @@ -136,6 +146,7 @@ public function run() $command->setOperations($this->operations); $command->setValidators($this->validators); $command->setInputs($this->inputs); + $command->setNormalizers($this->normalizers); $this->console->add($command); } @@ -180,4 +191,15 @@ public function addInput($id, $class) { $this->inputs->setInput($id, Container::resolve($class)); } + + /** + * Adds a new normalizer class + * + * @param string $id The instances ID + * @param string $class The fully qualified class name + */ + public function addNormalizer($id, $class) + { + $this->inputs->setInput($id, Container::resolve($class)); + } } diff --git a/src/Command/Command.php b/src/Command/Command.php index ee244b6..43588c0 100644 --- a/src/Command/Command.php +++ b/src/Command/Command.php @@ -13,6 +13,7 @@ abstract class Command extends Base use CommandInputs; use CommandOperations; use CommandValidators; + use CommandNormalizers; /** * @var SymfonyStyle diff --git a/src/Command/CommandNormalizers.php b/src/Command/CommandNormalizers.php new file mode 100644 index 0000000..553a837 --- /dev/null +++ b/src/Command/CommandNormalizers.php @@ -0,0 +1,29 @@ +normalizers = $normalizers; + } + + /** + * + */ + public function normalize($id, $value) + { + return $this->normalizers->getNormalizer($id)->normalize($value); + } +} diff --git a/src/Managers/NormalizerManager.php b/src/Managers/NormalizerManager.php new file mode 100644 index 0000000..7970312 --- /dev/null +++ b/src/Managers/NormalizerManager.php @@ -0,0 +1,64 @@ +normalizers[$id] = $instance; + } + + /** + * Checks if the normalizer exists + * + * @param string $id The normalizer ID + * + * @return boolean + */ + public function hasNormalizer($id) + { + return isset($this->normalizers[$id]); + } + + /** + * Gets a single normalizer + * + * @param string $id The normalizer ID + * + * @return AbstractNormalizer + */ + public function getNormalizer($id) + { + return $this->normalizers[$id] ?? null; + } + + /** + * Gets all registered normalizers + * + * @return array + */ + public function getnormalizers() + { + return $this->normalizers; + } +} diff --git a/src/Normalizers/AbstractNormalizer.php b/src/Normalizers/AbstractNormalizer.php new file mode 100644 index 0000000..676cf9d --- /dev/null +++ b/src/Normalizers/AbstractNormalizer.php @@ -0,0 +1,14 @@ + Date: Sun, 8 Jul 2018 21:45:06 +0800 Subject: [PATCH 4/4] Added support for normalizers --- example/Form/definition.yml | 19 +++++++++++++++-- src/App/Application.php | 2 +- src/Command/CommandInputs.php | 1 + src/Command/CommandNormalizers.php | 13 +++++++++++- src/Definition/DefinitionArguments.php | 27 ++++++++++++++++++++++++- src/Definition/DefinitionCommand.php | 5 ++++- src/Definition/DefinitionOperations.php | 4 ++-- src/Input/AskInput.php | 4 ++-- src/Normalizers/SnakeCase.php | 4 +--- src/Operations/AbstractOperation.php | 6 ------ src/Validators/EmptyValidator.php | 4 +++- 11 files changed, 69 insertions(+), 20 deletions(-) diff --git a/example/Form/definition.yml b/example/Form/definition.yml index 055a57f..43cfb17 100644 --- a/example/Form/definition.yml +++ b/example/Form/definition.yml @@ -14,11 +14,19 @@ inputs: default: DefaultForm validators: empty: - message: Form cannot be empty + message: Form name cannot be empty ends_with: message: Name should end with `Form` options: ['Form'] + id: + input: ask + message: What is the ID of the Form ? + default: ${name:(snake_case, strtolower)} + validators: + empty: + message: Form ID cannot be empty + template: input: confirm message: Do you want to have a twig template also ? @@ -38,7 +46,14 @@ actions: - action: copy if: template source: Form/template/template.html - target: ${path}/template.html.twig + target: ${path}/${id}.template.html.twig + + - action: yaml + target: Form/forms.yml + spaces: 2 + append: + forms: + ${id}: ${path}/${name} - action: notify message: Form generated successfully diff --git a/src/App/Application.php b/src/App/Application.php index d9c03b5..463ef56 100644 --- a/src/App/Application.php +++ b/src/App/Application.php @@ -200,6 +200,6 @@ public function addInput($id, $class) */ public function addNormalizer($id, $class) { - $this->inputs->setInput($id, Container::resolve($class)); + $this->normalizers->setNormalizer($id, Container::resolve($class)); } } diff --git a/src/Command/CommandInputs.php b/src/Command/CommandInputs.php index c12cf4b..dcb9472 100644 --- a/src/Command/CommandInputs.php +++ b/src/Command/CommandInputs.php @@ -30,6 +30,7 @@ public function input($id) $input = $this->inputs->getInput($id); $input->setOutput($this->style); + $input->setValidators($this->validators); return $input; } diff --git a/src/Command/CommandNormalizers.php b/src/Command/CommandNormalizers.php index 553a837..ea45571 100644 --- a/src/Command/CommandNormalizers.php +++ b/src/Command/CommandNormalizers.php @@ -24,6 +24,17 @@ public function setNormalizers(NormalizerManager $normalizers) */ public function normalize($id, $value) { - return $this->normalizers->getNormalizer($id)->normalize($value); + $normalizer = $this->normalizers->getNormalizer($id); + + // check if we have a registered normalizer with the specified ID + // if not just check if the a php method of that name exists and use + // that instead + if ($normalizer) { + $value = $normalizer->normalize($value); + } elseif (function_exists($id)) { + $value = $id($value); + } + + return $value; } } diff --git a/src/Definition/DefinitionArguments.php b/src/Definition/DefinitionArguments.php index 49318d9..e6ad579 100644 --- a/src/Definition/DefinitionArguments.php +++ b/src/Definition/DefinitionArguments.php @@ -27,9 +27,34 @@ private function resolveArguments($options, $vars) private function doReplaceArguments($value, $vars) { return preg_replace_callback('/\$\{(.*?)\}/', function ($matches) use ($vars) { + $rules = []; list($string, $match) = $matches; - return isset($vars[$match]) ? $vars[$match] : $string; + $definition = explode(':', $match); + + if (count($definition) === 2) { + list($match, $rules) = $definition; + } + + $value = isset($vars[$match]) ? $vars[$match] : $string; + + if (!empty($rules)) { + $ruleset = $this->doExtractRules($rules); + + foreach ($ruleset as $rule) { + $value = $this->normalize($rule, $value); + } + } + + return $value; }, $value); } + + private function doExtractRules($rules) + { + $rules = trim($rules, '()'); + $ruleset = explode(',', $rules); + + return array_map('trim', $ruleset); + } } diff --git a/src/Definition/DefinitionCommand.php b/src/Definition/DefinitionCommand.php index 861d19c..e0bcda9 100644 --- a/src/Definition/DefinitionCommand.php +++ b/src/Definition/DefinitionCommand.php @@ -50,6 +50,9 @@ public function execute(InputInterface $input, OutputInterface $output) } } + d($vars); + exit; + $operations = $this->yaml['actions'] ?? []; foreach ($operations as $key => $options) { @@ -68,7 +71,7 @@ public function execute(InputInterface $input, OutputInterface $output) } } - $this->handleOperation($action, $options, $vars); + // $this->handleOperation($action, $options, $vars); } } } diff --git a/src/Definition/DefinitionOperations.php b/src/Definition/DefinitionOperations.php index 172d808..f5e87f9 100644 --- a/src/Definition/DefinitionOperations.php +++ b/src/Definition/DefinitionOperations.php @@ -3,7 +3,7 @@ namespace Alexecus\Spawner\Definition; use ReflectionMethod; -use SebastianBergmann\CodeCoverage\RuntimeException; +use RuntimeException; use Alexecus\Spawner\Resolver\PathResource; @@ -35,7 +35,7 @@ public function handleOperation($name, $options, $vars) continue; } - new \RuntimeException("Missing argument `$key` for definition `$name`"); + new RuntimeException("Missing argument `$key` for definition `$name`"); } } diff --git a/src/Input/AskInput.php b/src/Input/AskInput.php index 0cc4d3f..db197e4 100644 --- a/src/Input/AskInput.php +++ b/src/Input/AskInput.php @@ -11,11 +11,11 @@ class AskInput extends AbstractInput { - public function perform($message, $default, $validations = []) + public function perform($message, $default = null, $validators = []) { $question = new Question($message, $default); - foreach ($validations as $key => $validation) { + foreach ($validators as $key => $validation) { $validator = $this->validators->getValidator($key); if ($validator) { diff --git a/src/Normalizers/SnakeCase.php b/src/Normalizers/SnakeCase.php index c7d7060..d5091b3 100644 --- a/src/Normalizers/SnakeCase.php +++ b/src/Normalizers/SnakeCase.php @@ -9,8 +9,6 @@ class SnakeCase extends AbstractNormalizer */ public function normalize($value) { - return strtolower( - preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $value) - ); + return preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $value); } } diff --git a/src/Operations/AbstractOperation.php b/src/Operations/AbstractOperation.php index aa53d95..3988aab 100644 --- a/src/Operations/AbstractOperation.php +++ b/src/Operations/AbstractOperation.php @@ -7,15 +7,9 @@ abstract class AbstractOperation { protected $output; - protected $validators; public function setOutput(StyleInterface $output) { $this->output = $output; } - - public function setValidators($validators) - { - $this->validators = $validators; - } } diff --git a/src/Validators/EmptyValidator.php b/src/Validators/EmptyValidator.php index b2dc14b..2075914 100644 --- a/src/Validators/EmptyValidator.php +++ b/src/Validators/EmptyValidator.php @@ -9,6 +9,8 @@ class EmptyValidator extends AbstractValidator */ public function validate($value, $options = []) { - return !empty($value); + $value = trim($value); + + return $value !== ''; } }