|
12 | 12 | namespace Symfony\Component\Form\Command;
|
13 | 13 |
|
14 | 14 | use Symfony\Component\Console\Command\Command;
|
| 15 | +use Symfony\Component\Console\Exception\InvalidArgumentException; |
15 | 16 | use Symfony\Component\Console\Input\InputArgument;
|
16 | 17 | use Symfony\Component\Console\Input\InputInterface;
|
17 | 18 | use Symfony\Component\Console\Input\InputOption;
|
@@ -48,6 +49,7 @@ protected function configure()
|
48 | 49 | $this
|
49 | 50 | ->setDefinition(array(
|
50 | 51 | new InputArgument('class', InputArgument::REQUIRED, 'The form type class'),
|
| 52 | + new InputArgument('option', InputArgument::OPTIONAL, 'The form type option'), |
51 | 53 | new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt or json)', 'txt'),
|
52 | 54 | ))
|
53 | 55 | ->setDescription('Displays form type information')
|
@@ -75,7 +77,30 @@ protected function execute(InputInterface $input, OutputInterface $output)
|
75 | 77 | $class = $this->getFqcnTypeClass($input, $io, $class);
|
76 | 78 | }
|
77 | 79 |
|
78 |
| - $object = $this->formRegistry->getType($class); |
| 80 | + $resolvedType = $this->formRegistry->getType($class); |
| 81 | + |
| 82 | + if ($option = $input->getArgument('option')) { |
| 83 | + $object = $resolvedType->getOptionsResolver(); |
| 84 | + if (!$object->isDefined($option)) { |
| 85 | + $message = sprintf('The option "%s" is not defined in the "%s" form type.', $option, get_class($resolvedType->getInnerType())); |
| 86 | + |
| 87 | + if ($alternatives = $this->findAlternatives($option, $object->getDefinedOptions())) { |
| 88 | + if (1 == count($alternatives)) { |
| 89 | + $message .= "\n\nDid you mean this?\n "; |
| 90 | + } else { |
| 91 | + $message .= "\n\nDid you mean one of these?\n "; |
| 92 | + } |
| 93 | + $message .= implode("\n ", $alternatives); |
| 94 | + } |
| 95 | + |
| 96 | + throw new InvalidArgumentException($message); |
| 97 | + } |
| 98 | + |
| 99 | + $options['type'] = $resolvedType->getInnerType(); |
| 100 | + $options['option'] = $option; |
| 101 | + } else { |
| 102 | + $object = $resolvedType; |
| 103 | + } |
79 | 104 |
|
80 | 105 | $helper = new DescriptorHelper();
|
81 | 106 | $options['format'] = $input->getOption('format');
|
@@ -103,4 +128,21 @@ private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, $shor
|
103 | 128 |
|
104 | 129 | return $io->choice(sprintf("The type \"%s\" is ambiguous.\n\n Select one of the following form types to display its information:", $shortClassName), $classes, $classes[0]);
|
105 | 130 | }
|
| 131 | + |
| 132 | + private function findAlternatives($name, array $collection) |
| 133 | + { |
| 134 | + $alternatives = array(); |
| 135 | + foreach ($collection as $item) { |
| 136 | + $lev = levenshtein($name, $item); |
| 137 | + if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { |
| 138 | + $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + $threshold = 1e3; |
| 143 | + $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; }); |
| 144 | + ksort($alternatives, SORT_NATURAL | SORT_FLAG_CASE); |
| 145 | + |
| 146 | + return array_keys($alternatives); |
| 147 | + } |
106 | 148 | }
|
0 commit comments