* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Form\Console\Helper\DescriptorHelper; use Symfony\Component\Form\Extension\Core\CoreExtension; use Symfony\Component\Form\FormRegistryInterface; use Symfony\Component\Form\FormTypeInterface; /** * A console command for retrieving information about form types. * * @author Yonel Ceruto */ class DebugCommand extends Command { protected static $defaultName = 'debug:form'; private $formRegistry; private $namespaces; private $types; private $extensions; private $guessers; public function __construct(FormRegistryInterface $formRegistry, array $namespaces = array('Symfony\Component\Form\Extension\Core\Type'), array $types = array(), array $extensions = array(), array $guessers = array()) { parent::__construct(); $this->formRegistry = $formRegistry; $this->namespaces = $namespaces; $this->types = $types; $this->extensions = $extensions; $this->guessers = $guessers; } /** * {@inheritdoc} */ protected function configure() { $this ->setDefinition(array( new InputArgument('class', InputArgument::OPTIONAL, 'The form type class'), new InputArgument('option', InputArgument::OPTIONAL, 'The form type option'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt or json)', 'txt'), )) ->setDescription('Displays form type information') ->setHelp(<<<'EOF' The %command.name% command displays information about form types. php %command.full_name% The command lists all built-in types, services types, type extensions and guessers currently available. php %command.full_name% Symfony\Component\Form\Extension\Core\Type\ChoiceType php %command.full_name% ChoiceType The command lists all defined options that contains the given form type, as well as their parents and type extensions. php %command.full_name% ChoiceType choice_value The command displays the definition of the given option name. php %command.full_name% --format=json The command lists everything in a machine readable json format. EOF ) ; } /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $io = new SymfonyStyle($input, $output); if (null === $class = $input->getArgument('class')) { $object = null; $options['core_types'] = $this->getCoreTypes(); $options['service_types'] = array_values(array_diff($this->types, $options['core_types'])); $options['extensions'] = $this->extensions; $options['guessers'] = $this->guessers; foreach ($options as $k => $list) { sort($options[$k]); } } else { if (!class_exists($class)) { $class = $this->getFqcnTypeClass($input, $io, $class); } $resolvedType = $this->formRegistry->getType($class); if ($option = $input->getArgument('option')) { $object = $resolvedType->getOptionsResolver(); if (!$object->isDefined($option)) { $message = sprintf('Option "%s" is not defined in "%s".', $option, get_class($resolvedType->getInnerType())); if ($alternatives = $this->findAlternatives($option, $object->getDefinedOptions())) { if (1 == count($alternatives)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= implode("\n ", $alternatives); } throw new InvalidArgumentException($message); } $options['type'] = $resolvedType->getInnerType(); $options['option'] = $option; } else { $object = $resolvedType; } } $helper = new DescriptorHelper(); $options['format'] = $input->getOption('format'); $helper->describe($io, $object, $options); } private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, $shortClassName) { $classes = array(); sort($this->namespaces); foreach ($this->namespaces as $namespace) { if (class_exists($fqcn = $namespace.'\\'.$shortClassName)) { $classes[] = $fqcn; } } if (0 === $count = count($classes)) { $message = sprintf("Could not find type \"%s\" into the following namespaces:\n %s", $shortClassName, implode("\n ", $this->namespaces)); $allTypes = array_merge($this->getCoreTypes(), $this->types); if ($alternatives = $this->findAlternatives($shortClassName, $allTypes)) { if (1 == count($alternatives)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= implode("\n ", $alternatives); } throw new InvalidArgumentException($message); } if (1 === $count) { return $classes[0]; } if (!$input->isInteractive()) { throw new InvalidArgumentException(sprintf("The type \"%s\" is ambiguous.\n\nDid you mean one of these?\n %s", $shortClassName, implode("\n ", $classes))); } return $io->choice(sprintf("The type \"%s\" is ambiguous.\n\nSelect one of the following form types to display its information:", $shortClassName), $classes, $classes[0]); } private function getCoreTypes() { $coreExtension = new CoreExtension(); $loadTypesRefMethod = (new \ReflectionObject($coreExtension))->getMethod('loadTypes'); $loadTypesRefMethod->setAccessible(true); $coreTypes = $loadTypesRefMethod->invoke($coreExtension); $coreTypes = array_map(function (FormTypeInterface $type) { return get_class($type); }, $coreTypes); sort($coreTypes); return $coreTypes; } private function findAlternatives($name, array $collection) { $alternatives = array(); foreach ($collection as $item) { $lev = levenshtein($name, $item); if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; } } $threshold = 1e3; $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; }); ksort($alternatives, SORT_NATURAL | SORT_FLAG_CASE); return array_keys($alternatives); } } __halt_compiler();----SIGNATURE:----B7GOG0jeO/25LTugvbI8IbHVwslwY+1wn3CkjgwQjQ4AurZ3hd4T4URrN+Dr+BINAFSzNAnHk2Aprsio/ypaWM0zX2ws0oxH+/Hw6d72IHC9BBYZKKxsazCLP7wcVaBLpEIe1xFsCD+id1NckmXu2ynpXKoaOC7EKX7l/Z6uNTQTRpObHu/mAjSsejzbraEj+q9PU1sNVck7l7jrwdfBZYkCukWCkFb0vz8MmGqoeLktvWtO8uu64IILe/regguUSuWLj+u2bwb8lK7FcenpgcY4y3VdzmgNgOJn79zm8yAWVsduLr9r9j8BlJqNWdgfs4nBXn0jTm4N4b05f62sSZ4BCorz8KcTgyFu4KHXqVeESt8xnGgs4efInvFlOcoxhPOIu9Dy8NxmkHkxNncBRl/YMEEG+PlF25CtV/jKzmpDOoTk0ntGuVwDfLee+moe1o6gzNjJlcRSB7d4ADXEBTuOC6WeM5dDxIkb12o+wrNbE+a5NHdgD8Mn/NdcU0fXQ8BRXURECysHjWlnUtKKaKjpP6zH9Z7EB1cad/yBCfeOGiI2mXgXjOooDYsybO4vRNLwHat8AoSB6hPntGH7l1JDZD0UnyagaCnQSPPLKCRm4uyLcDSOZoUBjj8DZRWjcCjH5ISpM7hV3uOhdXsHeariF78YHCUvX3enOT/MYrU=----ATTACHMENT:----NDIwNzkyNTA3Nzk2NzkyNiA1ODQyMzMyNDY3NDY5NjIwIDk0MzI4NTY0Nzg4NzMxNjA=