8000 Add debug:form command · symfony/symfony@4f040d7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4f040d7

Browse files
committed
Add debug:form command
1 parent d00ac8a commit 4f040d7

File tree

18 files changed

+917
-5
lines changed
  • DependencyInjection
  • Fixtures/Descriptor
  • Util
  • 18 files changed

    +917
    -5
    lines changed

    src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

    Lines changed: 2 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -220,6 +220,8 @@ public function load(array $configs, ContainerBuilder $container)
    220220
    if (!class_exists('Symfony\Component\Validator\Validation')) {
    221221
    throw new LogicException('The Validator component is required to use the Form component.');
    222222
    }
    223+
    } else {
    224+
    $container->removeDefinition('Symfony\Component\Form\Command\DebugCommand');
    223225
    }
    224226

    225227
    $this->registerSecurityCsrfConfiguration($config['csrf_protection'], $container, $loader);

    src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml

    Lines changed: 6 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -96,5 +96,11 @@
    9696
    <service id="Symfony\Bundle\FrameworkBundle\Command\YamlLintCommand">
    9797
    <tag name="con 1E79 sole.command" command="lint:yaml" />
    9898
    </service>
    99+
    100+
    <service id="Symfony\Component\Form\Command\DebugCommand">
    101+
    <argument type="service" id="form.registry" />
    102+
    <argument type="collection" /> <!-- All form types namespaces are stored here by FormPass -->
    103+
    <tag name="console.command" command="debug:form" />
    104+
    </service>
    99105
    </services>
    100106
    </container>

    src/Symfony/Bundle/FrameworkBundle/composer.json

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -40,7 +40,7 @@
    4040
    "symfony/dom-crawler": "~2.8|~3.0|~4.0",
    4141
    "symfony/polyfill-intl-icu": "~1.0",
    4242
    "symfony/security": "~2.8|~3.0|~4.0",
    43-
    "symfony/form": "~3.3|~4.0",
    43+
    "symfony/form": "~3.4|~4.0",
    4444
    "symfony/expression-language": "~2.8|~3.0|~4.0",
    4545
    "symfony/process": "~2.8|~3.0|~4.0",
    4646
    "symfony/security-core": "~3.2|~4.0",
    Lines changed: 96 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,96 @@
    1+
    <?php
    2+
    3+
    /*
    4+
    * This file is part of the Symfony package.
    5+
    *
    6+
    * (c) Fabien Potencier <fabien@symfony.com>
    7+
    *
    8+
    * For the full copyright and license information, please view the LICENSE
    9+
    * file that was distributed with this source code.
    10+
    */
    11+
    12+
    namespace Symfony\Component\Form\Command;
    13+
    14+
    use Symfony\Component\Console\Command\Command;
    15+
    use Symfony\Component\Console\Input\InputArgument;
    16+
    use Symfony\Component\Console\Input\InputInterface;
    17+
    use Symfony\Component\Console\Input\InputOption;
    18+
    use Symfony\Component\Console\Output\OutputInterface;
    19+
    use Symfony\Component\Console\Style\SymfonyStyle;
    20+
    use Symfony\Component\Form\Console\Helper\DescriptorHelper;
    21+
    use Symfony\Component\Form\FormRegistryInterface;
    22+
    23+
    /**
    24+
    * A console command for retrieving information about form types.
    25+
    *
    26+
    * @author Yonel Ceruto <yonelceruto@gmail.com>
    27+
    */
    28+
    class DebugCommand extends Command
    29+
    {
    30+
    protected static $defaultName = 'debug:form';
    31+
    32+
    private $formRegistry;
    33+
    private $namespaces;
    34+
    35+
    public function __construct(FormRegistryInterface $formRegistry, array $namespaces = array('Symfony\Component\Form\Extension\Core\Type'))
    36+
    {
    37+
    parent::__construct();
    38+
    39+
    $this->formRegistry = $formRegistry;
    40+
    $this->namespaces = $namespaces;
    41+
    }
    42+
    43+
    /**
    44+
    * {@inheritdoc}
    45+
    */
    46+
    protected function configure()
    47+
    {
    48+
    $this
    49+
    ->setDefinition(array(
    50+
    new InputArgument('class', InputArgument::REQUIRED, 'The form type class'),
    51+
    new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt or json)', 'txt'),
    52+
    ))
    53+
    ->setDescription('Displays form type information')
    54+
    ;
    55+
    }
    56+
    57+
    /**
    58+
    * {@inheritdoc}
    59+
    */
    60+
    protected function execute(InputInterface $input, OutputInterface $output)
    61+
    {
    62+
    $io = new SymfonyStyle($input, $output);
    63+
    64+
    if (!class_exists($class = $input->getArgument('class'))) {
    65+
    $class = $this->getFqcnTypeClass($input, $io, $class);
    66+
    }
    67+
    68+
    $object = $this->formRegistry->getType($class);
    69+
    70+
    $helper = new DescriptorHelper();
    71+
    $options['format'] = $input->getOption('format');
    72+
    $helper->describe($io, $object, $options);
    73+
    }
    74+
    75+
    private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, $shortClassName)
    76+
    {
    77+
    $classes = array();
    78+
    foreach ($this->namespaces as $namespace) {
    79+
    if (class_exists($fqcn = $namespace.'\\'.$shortClassName)) {
    80+
    $classes[] = $fqcn;
    81+
    }
    82+
    }
    83+
    84+
    if (0 === $count = count($classes)) {
    85+
    throw new \InvalidArgumentException(sprintf("Could not find type \"%s\" into the following namespaces:\n %s", $shortClassName, implode("\n ", $this->namespaces)));
    86+
    }
    87+
    if (1 === $count) {
    88+
    return $classes[0];
    89+
    }
    90+
    if (!$input->isInteractive()) {
    91+
    throw new \InvalidArgumentException(sprintf("The type \"%s\" is ambiguous.\nDid you mean one of these?\n %s", $shortClassName, implode("\n ", $classes)));
    92+
    }
    93+
    94+
    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]);
    95+
    }
    96+
    }
    Lines changed: 122 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,122 @@
    1+
    <?php
    2+
    3+
    /*
    4+
    * This file is part of the Symfony package.
    5+
    *
    6+
    * (c) Fabien Potencier <fabien@symfony.com>
    7+
    *
    8+
    * For the full copyright and license information, please view the LICENSE
    9+
    * file that was distributed with this source code.
    10+
    */
    11+
    12+
    namespace Symfony\Component\Form\Console\Descriptor;
    13+
    14+
    use Symfony\Component\Console\Descriptor\DescriptorInterface;
    15+
    use Symfony\Component\Console\Output\OutputInterface;
    16+
    use Symfony\Component\Console\Style\SymfonyStyle;
    17+
    use Symfony\Component\Form\ResolvedFormTypeInterface;
    18+
    use Symfony\Component\Form\Util\OptionsResolverWrapper;
    19+
    use Symfony\Component\OptionsResolver\OptionsResolver;
    20+
    21+
    /**
    22+
    * @author Yonel Ceruto <yonelceruto@gmail.com>
    23+
    *
    24+
    * @internal
    25+
    */
    26+
    abstract class Descriptor implements DescriptorInterface
    27+
    {
    28+
    /**
    29+
    * @var SymfonyStyle
    30+
    */
    31+
    protected $output;
    32+
    protected $type;
    33+
    protected $ownOptions = array();
    34+
    protected $overriddenOptions = array();
    35+
    protected $parentOptions = array();
    36+
    protected $extensionOptions = array();
    37+
    protected $requiredOptions = array();
    38+
    protected $parents = array();
    39+
    protected $extensions = array();
    40+
    41+
    /**
    42+
    * {@inheritdoc}
    43+
    */
    44+
    public function describe(OutputInterface $output, $object, array $options = array())
    45+
    {
    46+
    $this->output = $output;
    47+
    48+
    switch (true) {
    49+
    case $object instanceof ResolvedFormTypeInterface:
    50+
    $this->describeResolvedFormType($object, $options);
    51+
    break;
    52+
    default:
    53+
    throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object)));
    54+
    }
    55+
    }
    56+
    57+
    abstract protected function describeResolvedFormType(ResolvedFormTypeInterface $resolvedFormType, array $options = array());
    58+
    59+
    protected function collectOptions(ResolvedFormTypeInterface $type)
    60+
    {
    61+
    $this->parents = array();
    62+
    $this->extensions = array();
    63+
    64+
    if (null !== $type->getParent()) {
    65+
    $optionsResolver = clone $this->getParentOptionsResolver($type->getParent());
    66+
    } else {
    67+
    $optionsResolver = new OptionsResolver();
    68+
    }
    69+
    70+
    $type->getInnerType()->configureOptions($ownOptionsResolver = new OptionsResolverWrapper());
    71+
    $this->ownOptions = array_diff($ownOptionsResolver->getDefinedOptions(), $optionsResolver->getDefinedOptions());
    72+
    $overriddenOptions = array_intersect(array_merge($ownOptionsResolver->getDefinedOptions(), $ownOptionsResolver->getUndefinedOptions()), $optionsResolver->getDefinedOptions());
    73+
    74+
    $this->parentOptions = array();
    75+
    foreach ($this->parents as $class => $parentOptions) {
    76+
    $this->overriddenOptions[$class] = array_intersect($overriddenOptions, $parentOptions);
    77+
    $this->parentOptions[$class] = array_diff($parentOptions, $overriddenOptions);
    78+
    }
    79+
    80+
    $type->getInnerType()->configureOptions($optionsResolver);
    81+
    $this->collectTypeExtensionsOptions($type, $optionsResolver);
    82+
    $this->extensionOptions = array();
    83+
    foreach ($this->extensions as $class => $extensionOptions) {
    84+
    $this->overriddenOptions[$class] = array_intersect($overriddenOptions, $extensionOptions);
    85+
    $this->extensionOptions[$class] = array_diff($extensionOptions, $overriddenOptions);
    86+
    }
    87+
    88+
    $this->overriddenOptions = array_filter($this->overriddenOptions);
    89+
    $this->requiredOptions = $optionsResolver->getRequiredOptions();
    90+
    91+
    $this->parents = array_keys($this->parents);
    92+
    $this->extensions = array_keys($this->extensions);
    93+
    }
    94+
    95+
    private function getParentOptionsResolver(ResolvedFormTypeInterface $type)
    96+
    {
    97+
    $this->parents[$class = get_class($type->getInnerType())] = array();
    98+
    99+
    if (null !== $type->getParent()) {
    100+
    $optionsResolver = clone $this->getParentOptionsResolver($type->getParent());
    101+
    } else {
    102+
    $optionsResolver = new OptionsResolver();
    103+
    }
    104+
    105+
    $inheritedOptions = $optionsResolver->getDefinedOptions();
    106+
    $type->getInnerType()->configureOptions($optionsResolver);
    107+
    $this->parents[$class] = array_diff($optionsResolver->getDefinedOptions(), $inheritedOptions);
    108+
    109+
    $this->collectTypeExtensionsOptions($type, $optionsResolver);
    110+
    111+
    return $optionsResolver;
    112+
    }
    113+
    114+
    private function collectTypeExtensionsOptions(ResolvedFormTypeInterface $type, OptionsResolver $optionsResolver)
    115+
    {
    116+
    foreach ($type->getTypeExtensions() as $extension) {
    117+
    $inheritedOptions = $optionsResolver->getDefinedOptions();
    118+
    $extension->configureOptions($optionsResolver);
    119+
    $this->extensions[get_class($extension)] = array_diff($optionsResolver->getDefinedOptions(), $inheritedOptions);
    120+
    }
    121+
    }
    122+
    }
    Lines changed: 68 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,68 @@
    1+
    <?php
    2+
    3+
    /*
    4+
    * This file is part of the Symfony package.
    5+
    *
    6+
    * (c) Fabien Potencier <fabien@symfony.com>
    7+
    *
    8+
    * For the full copyright and license information, please view the LICENSE
    9+
    * file that was distributed with this source code.
    10+
    */
    11+
    12+
    namespace Symfony\Component\Form\Console\Descriptor;
    13+
    14+
    use Symfony\Component\Form\ResolvedFormTypeInterface;
    15+
    16+
    /**
    17+
    * @author Yonel Ceruto <yonelceruto@gmail.com>
    18+
    *
    19+
    * @internal
    20+
    */
    21+
    class JsonDescriptor extends Descriptor
    22+
    {
    23+
    protected function describeResolvedFormType(ResolvedFormTypeInterface $resolvedFormType, array $options = array())
    24+
    {
    25+
    $this->collectOptions($resolvedFormType);
    26+
    27+
    $formOptions = array(
    28+
    'own' => $this->ownOptions,
    29+
    'overridden' => $this->overriddenOptions,
    30+
    'parent' => $this->parentOptions,
    31+
    'extension' => $this->extensionOptions,
    32+
    'required' => $this->requiredOptions,
    33+
    );
    34+
    $this->sortOptions($formOptions);
    35+
    36+
    $data = array(
    37+
    'class' => get_class($resolvedFormType->getInnerType()),
    38+
    'block_prefix' => $resolvedFormType->getInnerType()->getBlockPrefix(),
    39+
    'options' => $formOptions,
    40+
    'parent_types' => $this->parents,
    41+
    'type_extensions' => $this->extensions,
    42+
    );
    43+
    44+
    $this->writeData($data, $options);
    45+
    }
    46+
    47+
    private function writeData(array $data, array $options)
    48+
    {
    49+
    $flags = isset($options['json_encoding']) ? $options['json_encoding'] : 0;
    50+
    $this->output->write(json_encode($data, $flags | JSON_PRETTY_PRINT)."\n");
    51+
    }
    52+
    53+
    private function sortOptions(array &$options)
    54+
    {
    55+
    foreach ($options as &$opts) {
    56+
    $sorted = false;
    57+
    foreach ($opts as &$opt) {
    58+
    if (is_array($opt)) {
    59+
    sort($opt);
    60+
    $sorted = true;
    61+
    }
    62+
    }
    63+
    if (!$sorted) {
    64+
    sort($opts);
    65+
    }
    66+
    }
    67+
    }
    68+
    }

    0 commit comments

    Comments
     (0)
    0