Skip to content

Commit 09ae04d

Browse files
committed
Merge branch '3.4'
* 3.4: [HttpKernel] Fix loading legacy 3.3 containers in 3.4 context [TwigBundle] require twig-bridge ~3.4 [Yaml] mark some classes as final Fixed the escaping of back slashes and << in console output Add debug:form command bumped Symfony version to 2.8.28 updated VERSION for 2.8.27 updated CHANGELOG for 2.8.27 bumped Symfony version to 2.7.35 updated VERSION for 2.7.34 update CONTRIBUTORS for 2.7.34 updated CHANGELOG for 2.7.34
2 parents 0898e9f + bf17bcb commit 09ae04d

File tree

15 files changed

+906
-2
lines changed

15 files changed

+906
-2
lines changed

Command/DebugCommand.php

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 <[email protected]>
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 <[email protected]>
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+
}

Console/Descriptor/Descriptor.php

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 <[email protected]>
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 <[email protected]>
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+
}

Console/Descriptor/JsonDescriptor.php

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 <[email protected]>
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 <[email protected]>
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+
}

Console/Descriptor/TextDescriptor.php

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Helper\TableSeparator;
15+
use Symfony\Component\Form\ResolvedFormTypeInterface;
16+
17+
/**
18+
* @author Yonel Ceruto <[email protected]>
19+
*
20+
* @internal
21+
*/
22+
class TextDescriptor extends Descriptor
23+
{
24+
protected function describeResolvedFormType(ResolvedFormTypeInterface $resolvedFormType, array $options = array())
25+
{
26+
$this->collectOptions($resolvedFormType);
27+
28+
$formOptions = $this->normalizeAndSortOptionsColumns(array_filter(array(
29+
'own' => $this->ownOptions,
30+
'overridden' => $this->overriddenOptions,
31+
'parent' => $this->parentOptions,
32+
'extension' => $this->extensionOptions,
33+
)));
34+
35+
// setting headers and column order
36+
$tableHeaders = array_intersect_key(array(
37+
'own' => 'Options',
38+
'overridden' => 'Overridden options',
39+
'parent' => 'Parent options',
40+
'extension' => 'Extension options',
41+
), $formOptions);
42+
43+
$tableRows = array();
44+
$count = count(max($formOptions));
45+
for ($i = 0; $i < $count; ++$i) {
46+
$cells = array();
47+
foreach (array_keys($tableHeaders) as $group) {
48+
if (isset($formOptions[$group][$i])) {
49+
$option = $formOptions[$group][$i];
50+
51+
if (is_string($option) && in_array($option, $this->requiredOptions)) {
52+
$option .= ' <info>(required)</info>';
53+
}
54+
55+
$cells[] = $option;
56+
} else {
57+
$cells[] = null;
58+
}
59+
}
60+
$tableRows[] = $cells;
61+
}
62+
63+
$this->output->title(sprintf('%s (Block prefix: "%s")', get_class($resolvedFormType->getInnerType()), $resolvedFormType->getInnerType()->getBlockPrefix()));
64+
$this->output->table($tableHeaders, $tableRows);
65+
66+
if ($this->parents) {
67+
$this->output->section('Parent types');
68+
$this->output->listing($this->parents);
69+
}
70+
71+
if ($this->extensions) {
72+
$this->output->section('Type extensions');
73+
$this->output->listing($this->extensions);
74+
}
75+
}
76+
77+
private function normalizeAndSortOptionsColumns(array $options)
78+
{
79+
foreach ($options as $group => &$opts) {
80+
$sorted = false;
81+
foreach ($opts as $class => $opt) {
82+
if (!is_array($opt) || 0 === count($opt)) {
83+
continue;
84+
}
85+
86+
unset($opts[$class]);
87+
88+
if (!$sorted) {
89+
$opts = array();
90+
} else {
91+
$opts[] = null;
92+
}
93+
$opts[] = sprintf('<info>%s</info>', (new \ReflectionClass($class))->getShortName());
94+
$opts[] = new TableSeparator();
95+
96+
sort($opt);
97+
$sorted = true;
98+
$opts = array_merge($opts, $opt);
99+
}
100+
101+
if (!$sorted) {
102+
sort($opts);
103+
}
104+
}
105+
106+
return $options;
107+
}
108+
}

0 commit comments

Comments
 (0)