Skip to content

[Config] Add comment on array methods #44171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 40 additions & 21 deletions src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Config\Builder;

use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\BaseNode;
use Symfony\Component\Config\Definition\BooleanNode;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\EnumNode;
Expand Down Expand Up @@ -123,14 +124,18 @@ private function buildNode(NodeInterface $node, ClassBuilder $class, string $nam

private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $namespace): void
{
if ('' !== $comment = $this->getComment($node)) {
$comment = "/**\n$comment*/\n";
}

$childClass = new ClassBuilder($namespace, $node->getName());
$childClass->setAllowExtraKeys($node->shouldIgnoreExtraKeys());
$class->addRequire($childClass);
$this->classes[] = $childClass;

$property = $class->addProperty($node->getName(), $childClass->getFqcn());
$body = '
public function NAME(array $value = []): CLASS
COMMENTpublic function NAME(array $value = []): CLASS
{
if (null === $this->PROPERTY) {
$this->PROPERTY = new CLASS($value);
Expand All @@ -141,7 +146,7 @@ public function NAME(array $value = []): CLASS
return $this->PROPERTY;
}';
$class->addUse(InvalidConfigurationException::class);
$class->addMethod($node->getName(), $body, ['PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn()]);
$class->addMethod($node->getName(), $body, ['COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn()]);

$this->buildNode($node, $childClass, $this->getSubNamespace($childClass));
}
Expand Down Expand Up @@ -218,16 +223,20 @@ public function NAME(string $VAR, TYPE $VALUE): static
$this->classes[] = $childClass;
$property = $class->addProperty($node->getName(), $childClass->getFqcn().'[]');

if ('' !== $comment = $this->getComment($node)) {
$comment = "/**\n$comment*/\n";
}

if (null === $key = $node->getKeyAttribute()) {
$body = '
public function NAME(array $value = []): CLASS
COMMENTpublic function NAME(array $value = []): CLASS
{
return $this->PROPERTY[] = new CLASS($value);
}';
$class->addMethod($methodName, $body, ['PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn()]);
$class->addMethod($methodName, $body, ['COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn()]);
} else {
$body = '
public function NAME(string $VAR, array $VALUE = []): CLASS
COMMENTpublic function NAME(string $VAR, array $VALUE = []): CLASS
{
if (!isset($this->PROPERTY[$VAR])) {
return $this->PROPERTY[$VAR] = new CLASS($value);
Expand All @@ -239,7 +248,7 @@ public function NAME(string $VAR, array $VALUE = []): CLASS
throw new InvalidConfigurationException(\'The node created by "NAME()" has already been initialized. You cannot pass values the second time you call NAME().\');
}';
$class->addUse(InvalidConfigurationException::class);
$class->addMethod($methodName, $body, ['PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn(), 'VAR' => '' === $key ? 'key' : $key, 'VALUE' => 'value' === $key ? 'data' : 'value']);
$class->addMethod($methodName, $body, ['COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn(), 'VAR' => '' === $key ? 'key' : $key, 'VALUE' => 'value' === $key ? 'data' : 'value']);
}

$this->buildNode($prototype, $childClass, $namespace.'\\'.$childClass->getName());
Expand Down Expand Up @@ -296,31 +305,41 @@ private function getParameterType(NodeInterface $node): ?string
return null;
}

private function getComment(VariableNode $node): string
private function getComment(BaseNode $node): string
{
$comment = '';
if ('' !== $info = (string) $node->getInfo()) {
$comment .= ' * '.$info."\n";
}

foreach ((array) ($node->getExample() ?? []) as $example) {
$comment .= ' * @example '.$example."\n";
}
if (!$node instanceof ArrayNode) {
foreach ((array) ($node->getExample() ?? []) as $example) {
$comment .= ' * @example '.$example."\n";
}

if ('' !== $default = $node->getDefaultValue()) {
$comment .= ' * @default '.(null === $default ? 'null' : var_export($default, true))."\n";
}
if ('' !== $default = $node->getDefaultValue()) {
$comment .= ' * @default '.(null === $default ? 'null' : var_export($default, true))."\n";
}

if ($node instanceof EnumNode) {
$comment .= sprintf(' * @param ParamConfigurator|%s $value', implode('|', array_map(function ($a) {
return var_export($a, true);
}, $node->getValues())))."\n";
if ($node instanceof EnumNode) {
$comment .= sprintf(' * @param ParamConfigurator|%s $value', implode('|', array_map(function ($a) {
return var_export($a, true);
}, $node->getValues())))."\n";
} else {
$parameterType = $this->getParameterType($node);
if (null === $parameterType || '' === $parameterType) {
$parameterType = 'mixed';
}
$comment .= ' * @param ParamConfigurator|'.$parameterType.' $value'."\n";
}
} else {
$parameterType = $this->getParameterType($node);
if (null === $parameterType || '' === $parameterType) {
$parameterType = 'mixed';
foreach ((array) ($node->getExample() ?? []) as $example) {
$comment .= ' * @example '.json_encode($example)."\n";
}

if ($node->hasDefaultValue() && [] != $default = $node->getDefaultValue()) {
$comment .= ' * @default '.json_encode($default)."\n";
}
$comment .= ' * @param ParamConfigurator|'.$parameterType.' $value'."\n";
}

if ($node->isDeprecated()) {
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Config/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ CHANGELOG
---

* Allow using environment variables in `EnumNode`
* Add Node's information in generated Config

6.0
---
Expand Down
16 changes: 16 additions & 0 deletions src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ public function getConfigTreeBuilder(): TreeBuilder
->useAttributeAsKey('source_class')
->prototype('scalar')->end()
->end()
->arrayNode('books')
->children()
->arrayNode('page')
->example('page 1')
->defaultValue(['number' => 1, 'content' => ''])
->prototype('array')
->children()
->integerNode('number')->end()
->scalarNode('content')->end()
->end()
->end()
->end()
->end()
->info('looks for translation in old fashion way')
->setDeprecated('symfony/config', '6.0')
->end()
->end()
->end()
->arrayNode('messenger')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace Symfony\Config\AddToList\Translator\Books;


use Symfony\Component\Config\Loader\ParamConfigurator;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;


/**
* This class is automatically generated to help creating config.
*/
class PageConfig
{
private $number;
private $content;

/**
* @default null
* @param ParamConfigurator|int $value
* @return $this
*/
public function number($value): static
{
$this->number = $value;

return $this;
}

/**
* @default null
* @param ParamConfigurator|mixed $value
* @return $this
*/
public function content($value): static
{
$this->content = $value;

return $this;
}

public function __construct(array $value = [])
{

if (isset($value['number'])) {
$this->number = $value['number'];
unset($value['number']);
}

if (isset($value['content'])) {
$this->content = $value['content'];
unset($value['content']);
}

if ([] !== $value) {
throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value)));
}
}

public function toArray(): array
{
$output = [];
if (null !== $this->number) {
$output['number'] = $this->number;
}
if (null !== $this->content) {
$output['content'] = $this->content;
}

return $output;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Symfony\Config\AddToList\Translator;

require_once __DIR__.\DIRECTORY_SEPARATOR.'Books'.\DIRECTORY_SEPARATOR.'PageConfig.php';

use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;


/**
* This class is automatically generated to help creating config.
*/
class BooksConfig
{
private $page;

/**
* @example "page 1"
* @default {"number":1,"content":""}
*/
public function page(array $value = []): \Symfony\Config\AddToList\Translator\Books\PageConfig
{
return $this->page[] = new \Symfony\Config\AddToList\Translator\Books\PageConfig($value);
}

public function __construct(array $value = [])
{

if (isset($value['page'])) {
$this->page = array_map(function ($v) { return new \Symfony\Config\AddToList\Translator\Books\PageConfig($v); }, $value['page']);
unset($value['page']);
}

if ([] !== $value) {
throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value)));
}
}

public function toArray(): array
{
$output = [];
if (null !== $this->page) {
$output['page'] = array_map(function ($v) { return $v->toArray(); }, $this->page);
}

return $output;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Symfony\Config\AddToList;

require_once __DIR__.\DIRECTORY_SEPARATOR.'Translator'.\DIRECTORY_SEPARATOR.'BooksConfig.php';

use Symfony\Component\Config\Loader\ParamConfigurator;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
Expand All @@ -14,6 +15,7 @@ class TranslatorConfig
{
private $fallbacks;
private $sources;
private $books;

/**
* @param ParamConfigurator|list<ParamConfigurator|mixed> $value
Expand All @@ -37,6 +39,21 @@ public function source(string $source_class, mixed $value): static
return $this;
}

/**
* looks for translation in old fashion way
* @deprecated The child node "books" at path "translator" is deprecated.
*/
public function books(array $value = []): \Symfony\Config\AddToList\Translator\BooksConfig
{
if (null === $this->books) {
$this->books = new \Symfony\Config\AddToList\Translator\BooksConfig($value);
} elseif ([] !== $value) {
throw new InvalidConfigurationException('The node created by "books()" has already been initialized. You cannot pass values the second time you call books().');
}

return $this->books;
}

public function __construct(array $value = [])
{

Expand All @@ -50,6 +67,11 @@ public function __construct(array $value = [])
unset($value['sources']);
}

if (isset($value['books'])) {
$this->books = new \Symfony\Config\AddToList\Translator\BooksConfig($value['books']);
unset($value['books']);
}

if ([] !== $value) {
throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value)));
}
Expand All @@ -64,6 +86,9 @@ public function toArray(): array
if (null !== $this->sources) {
$output['sources'] = $this->sources;
}
if (null !== $this->books) {
$output['books'] = $this->books->toArray();
}

return $output;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->children()
->booleanNode('enabled')->defaultFalse()->end()
->floatNode('favorite_float')->end()
->arrayNode('good_integers')
->arrayNode('good_integers')
->integerPrototype()->end()
->end()
->end()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ public function testConfig(string $name, string $alias)
$expectedCode = $basePath.$name;

// to regenerate snapshot files, uncomment these lines
// (new Filesystem())->remove($expectedCode);
// $configBuilder = $this->generateConfigBuilder('Symfony\\Component\\Config\\Tests\\Builder\\Fixtures\\'.$name, $expectedCode);
//(new Filesystem())->remove($expectedCode);
//$this->generateConfigBuilder('Symfony\\Component\\Config\\Tests\\Builder\\Fixtures\\'.$name, $expectedCode);
//$this->markTestIncomplete('Re-comment the line above and relaunch the tests');

$outputDir = sys_get_temp_dir().\DIRECTORY_SEPARATOR.uniqid('sf_config_builder', true);
$configBuilder = $this->generateConfigBuilder('Symfony\\Component\\Config\\Tests\\Builder\\Fixtures\\'.$name, $outputDir);
Expand Down