diff --git a/src/Column.php b/src/Column.php index b2cfa16..ec1ca1a 100644 --- a/src/Column.php +++ b/src/Column.php @@ -98,7 +98,7 @@ public static function askMulti(bool $extension = false): array label: '¿Desea crear los campos habituales? (No = Default)' ); - if ($prompt === 'Si') { + if ($prompt === 'si') { $fields[] = new Column([ 'display' => 'none', 'nombre' => 'id', @@ -539,8 +539,8 @@ private function askRequerido(): void { do { $requerido = Utils::promptYesOrNo("¿El campo {$this->nombre} es obligatorio? (No = predeterminado)"); - $this->requerido = $requerido === 'Si'; - } while ($requerido !== 'Si' && $requerido !== 'No'); + $this->requerido = $requerido === 'si'; + } while ($requerido !== 'si' && $requerido !== 'no'); } private function askStep(): void diff --git a/src/Command/Controller/ControllerCommand.php b/src/Command/Controller/ControllerCommand.php index 208137e..26cf428 100644 --- a/src/Command/Controller/ControllerCommand.php +++ b/src/Command/Controller/ControllerCommand.php @@ -93,7 +93,7 @@ private function createController(string $name): void hint: 'El nombre que se colocará en "$data[\'menu\'] = \'NOMBRE_ELEGIDO\';", por defecto es "admin".' ); - $createView = 'Si' === Utils::promptYesOrNo( + $createView = 'si' === Utils::promptYesOrNo( label: '¿Desea añadir la vista twig?' ); diff --git a/src/Command/Model/ModelCommand.php b/src/Command/Model/ModelCommand.php index 9f199ff..ca964f9 100644 --- a/src/Command/Model/ModelCommand.php +++ b/src/Command/Model/ModelCommand.php @@ -67,12 +67,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int } Utils::echo("\n"); - if (Utils::promptYesOrNo('¿Crear EditController? (No - predeterminado)') === 'Si') { + if (Utils::promptYesOrNo('¿Crear EditController? (No - predeterminado)') === 'si') { $this->createEditController($name, $fields); } Utils::echo("\n"); - if (Utils::promptYesOrNo('¿Crear ListController? (No - predeterminado)') === 'Si') { + if (Utils::promptYesOrNo('¿Crear ListController? (No - predeterminado)') === 'si') { $this->createListController($name, $fields); } diff --git a/src/Console/Application.php b/src/Console/Application.php index 3a0db8b..b7e1afc 100644 --- a/src/Console/Application.php +++ b/src/Console/Application.php @@ -5,10 +5,18 @@ namespace fsmaker\Console; +use Laravel\Prompts\MultiSelectPrompt; +use Laravel\Prompts\Prompt; +use Laravel\Prompts\SelectPrompt; +use Laravel\Prompts\TextPrompt; use Symfony\Component\Console\Application as BaseApplication; use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Style\SymfonyStyle; class Application extends BaseApplication { @@ -18,6 +26,119 @@ public function __construct() $this->addCommands($this->getCommands()); } + public function doRun(InputInterface $input, OutputInterface $output): int + { + // Fix para windows (la librería prompt no lo soporta) + Prompt::fallbackWhen(PHP_OS_FAMILY === 'Windows'); + // Prompt::fallbackWhen(true); // para tests + + $io = new SymfonyStyle($input, $output); + + TextPrompt::fallbackUsing(function (TextPrompt $prompt) use ($io) { + while (true) { + $value = $io->ask($prompt->label, $prompt->default); + + if ($prompt->validate) { + $error = ($prompt->validate)($value ?? ''); + if (is_string($error) && strlen($error) > 0) { + $io->writeln("Error: $error"); + continue; + } + } + return (string)$value; + } + }); + + SelectPrompt::fallbackUsing(function (SelectPrompt $prompt) use ($io) { + $question = new ChoiceQuestion($prompt->label, $prompt->options, $prompt->default); + // Capturar el validador por defecto + $validator = $question->getValidator(); + + $question->setValidator(function ($answer) { + return $answer; + }); + + while (true) { + // Aquí el askQuestion llamará a nuestro validador nulo. + $answer = $io->askQuestion($question); + + try { + // Validar manualmente con el validador original. + // El validador original espera el valor tal cual sale del normalizador interno. + $choice = $validator($answer); + + // Ensure we return the key if options are associative + if (array_is_list($prompt->options)) { + return $choice; + } + return array_search($choice, $prompt->options) ?: $choice; + } catch (\Exception $e) { + $msg = $e->getMessage(); + if (preg_match('/^Value "(.*)" is invalid$/', $msg, $matches)) { + $msg = "El valor \"{$matches[1]}\" es inválido"; + } + $io->writeln("Error: $msg"); + } + } + }); + + MultiSelectPrompt::fallbackUsing(function (MultiSelectPrompt $prompt) use ($io) { + $default = $prompt->default; + if (is_array($default) && !empty($default)) { + $default = implode(',', $default); + } elseif (empty($default)) { + $default = null; + } + + $question = new ChoiceQuestion($prompt->label, $prompt->options, $default); + $question->setMultiselect(true); + + // Normalizador para permitir separar por espacios además de comas + $question->setNormalizer(function ($value) { + if ($value === null) { + return $value; + } + // Reemplaza uno o más espacios/comas con una sola coma + return preg_replace('/[\s,]+/', ',', trim($value)); + }); + + // Capturar el validador por defecto + $validator = $question->getValidator(); + // Anular el validador en la pregunta + $question->setValidator(function ($answer) { + return $answer; + }); + + while (true) { + $result = $io->askQuestion($question); + try { + // Validar manualmente + $result = $validator($result); + + if (array_is_list($prompt->options)) { + return $result; + } + + // Map values back to keys + $mapped = []; + foreach ($result as $val) { + $key = array_search($val, $prompt->options); + $mapped[] = $key !== false ? $key : $val; + } + return $mapped; + } catch (\Exception $e) { + $msg = $e->getMessage(); + if (preg_match('/^Value "(.*)" is invalid$/', $msg, $matches)) { + $msg = "El valor \"{$matches[1]}\" es inválido"; + } + $io->writeln("Error: $msg"); + } + } + }); + + return parent::doRun($input, $output); + } + /** * Esto es para definir solo las opciones existentes (en fsmaker no existen opciones) */ diff --git a/src/Utils.php b/src/Utils.php index c6f6150..aaf3e83 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -116,17 +116,17 @@ public static function prompt(string $label, string $placeholder = '', string $d } /** - * Muestra un prompt de elegir si o no, devuelve 'Si' o 'No' + * Muestra un prompt de elegir si o no, devuelve 'si' o 'no' */ public static function promptYesOrNo(string $label, bool $noPorDefecto = true): string { return select( label: $label, options: [ // 'valor que devuelve' => 'key que se muestra al usuario a elegir' - 'Si' => 'Si', - 'No' => 'No' + 'si' => 'Si', + 'no' => 'No' ], - default: $noPorDefecto ? 'No' : 'Si', + default: $noPorDefecto ? 'no' : 'si', scroll: 2, // cantidad de opciones a mostrar a la vez en pantalla (el resto scroll) required: true );