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 2eb49c1..463ef56 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(); } @@ -69,6 +77,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); @@ -76,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); } /** @@ -135,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); } @@ -179,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->normalizers->setNormalizer($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/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 new file mode 100644 index 0000000..ea45571 --- /dev/null +++ b/src/Command/CommandNormalizers.php @@ -0,0 +1,40 @@ +normalizers = $normalizers; + } + + /** + * + */ + public function normalize($id, $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 new file mode 100644 index 0000000..e6ad579 --- /dev/null +++ b/src/Definition/DefinitionArguments.php @@ -0,0 +1,60 @@ + $value) { + $key = $this->doReplaceArguments($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) { + $rules = []; + list($string, $match) = $matches; + + $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 14b9e9c..e0bcda9 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,37 @@ 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); } } + d($vars); + exit; + $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']; + + $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, $operation, $vars); + // $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..f5e87f9 100644 --- a/src/Definition/DefinitionOperations.php +++ b/src/Definition/DefinitionOperations.php @@ -2,9 +2,10 @@ namespace Alexecus\Spawner\Definition; +use ReflectionMethod; +use RuntimeException; + use Alexecus\Spawner\Resolver\PathResource; -use \ReflectionMethod; -use SebastianBergmann\CodeCoverage\RuntimeException; trait DefinitionOperations { @@ -15,18 +16,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) { @@ -45,30 +35,11 @@ public function handleOperation($name, $options, $vars) continue; } - new \RuntimeException("Missing argument `$key` for definition `$name`"); + new RuntimeException("Missing argument `$key` for definition `$name`"); } } $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/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/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 @@ +output = $output; } - - public function setValidators($validators) - { - $this->validators = $validators; - } } diff --git a/src/Operations/Yaml.php b/src/Operations/Yaml.php new file mode 100644 index 0000000..a8a225d --- /dev/null +++ b/src/Operations/Yaml.php @@ -0,0 +1,50 @@ +filesystem = $filesystem; + } + + /** + * Performs the yaml operation + */ + public function perform(PathResource $target, array $append, $spaces = 2) + { + $data = []; + + try { + $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_recursive($data, $append); + $yaml = Parser::dump($data, 2, $spaces); + + $this->filesystem->dumpFile($target->getAbsolute(), $yaml); + } +} 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 !== ''; } }