![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/rector/rector/vendor/symfony/config/Builder/ |
<?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <[email protected]> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace RectorPrefix202308\Symfony\Component\Config\Builder; use RectorPrefix202308\Symfony\Component\Config\Definition\ArrayNode; use RectorPrefix202308\Symfony\Component\Config\Definition\BaseNode; use RectorPrefix202308\Symfony\Component\Config\Definition\BooleanNode; use RectorPrefix202308\Symfony\Component\Config\Definition\Builder\ExprBuilder; use RectorPrefix202308\Symfony\Component\Config\Definition\ConfigurationInterface; use RectorPrefix202308\Symfony\Component\Config\Definition\EnumNode; use RectorPrefix202308\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use RectorPrefix202308\Symfony\Component\Config\Definition\FloatNode; use RectorPrefix202308\Symfony\Component\Config\Definition\IntegerNode; use RectorPrefix202308\Symfony\Component\Config\Definition\NodeInterface; use RectorPrefix202308\Symfony\Component\Config\Definition\PrototypedArrayNode; use RectorPrefix202308\Symfony\Component\Config\Definition\ScalarNode; use RectorPrefix202308\Symfony\Component\Config\Definition\VariableNode; use RectorPrefix202308\Symfony\Component\Config\Loader\ParamConfigurator; /** * Generate ConfigBuilders to help create valid config. * * @author Tobias Nyholm <[email protected]> */ class ConfigBuilderGenerator implements ConfigBuilderGeneratorInterface { /** * @var ClassBuilder[] */ private $classes = []; /** * @var string */ private $outputDir; public function __construct(string $outputDir) { $this->outputDir = $outputDir; } /** * @return \Closure that will return the root config class */ public function build(ConfigurationInterface $configuration) : \Closure { $this->classes = []; $rootNode = $configuration->getConfigTreeBuilder()->buildTree(); $rootClass = new ClassBuilder('RectorPrefix202308\\Symfony\\Config', $rootNode->getName()); $path = $this->getFullPath($rootClass); if (!\is_file($path)) { // Generate the class if the file not exists $this->classes[] = $rootClass; $this->buildNode($rootNode, $rootClass, $this->getSubNamespace($rootClass)); $rootClass->addImplements(ConfigBuilderInterface::class); $rootClass->addMethod('getExtensionAlias', ' public function NAME(): string { return \'ALIAS\'; }', ['ALIAS' => $rootNode->getPath()]); $this->writeClasses(); } return function () use($path, $rootClass) { require_once $path; $className = $rootClass->getFqcn(); return new $className(); }; } private function getFullPath(ClassBuilder $class) : string { $directory = $this->outputDir . \DIRECTORY_SEPARATOR . $class->getDirectory(); if (!\is_dir($directory)) { @\mkdir($directory, 0777, \true); } return $directory . \DIRECTORY_SEPARATOR . $class->getFilename(); } private function writeClasses() : void { foreach ($this->classes as $class) { $this->buildConstructor($class); $this->buildToArray($class); if ($class->getProperties()) { $class->addProperty('_usedProperties', null, '[]'); } $this->buildSetExtraKey($class); \file_put_contents($this->getFullPath($class), $class->build()); } $this->classes = []; } private function buildNode(NodeInterface $node, ClassBuilder $class, string $namespace) : void { if (!$node instanceof ArrayNode) { throw new \LogicException('The node was expected to be an ArrayNode. This Configuration includes an edge case not supported yet.'); } foreach ($node->getChildren() as $child) { switch (\true) { case $child instanceof ScalarNode: $this->handleScalarNode($child, $class); break; case $child instanceof PrototypedArrayNode: $this->handlePrototypedArrayNode($child, $class, $namespace); break; case $child instanceof VariableNode: $this->handleVariableNode($child, $class); break; case $child instanceof ArrayNode: $this->handleArrayNode($child, $class, $namespace); break; default: throw new \RuntimeException(\sprintf('Unknown node "%s".', \get_class($child))); } } } private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $namespace) : void { $childClass = new ClassBuilder($namespace, $node->getName()); $childClass->setAllowExtraKeys($node->shouldIgnoreExtraKeys()); $class->addRequire($childClass); $this->classes[] = $childClass; $hasNormalizationClosures = $this->hasNormalizationClosures($node); $comment = $this->getComment($node); if ($hasNormalizationClosures) { $comment = \sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment); $comment .= \sprintf(' * @return %s|$this' . "\n", $childClass->getFqcn()); $comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)' . "\n ", $childClass->getFqcn()); } if ('' !== $comment) { $comment = "/**\n{$comment}*/\n"; } $property = $class->addProperty($node->getName(), $this->getType($childClass->getFqcn(), $hasNormalizationClosures)); $nodeTypes = $this->getParameterTypes($node); $body = $hasNormalizationClosures ? ' COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static { if (!\\is_array($value)) { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY = $value; return $this; } if (!$this->PROPERTY instanceof CLASS) { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY = new CLASS($value); } elseif (0 < \\func_num_args()) { throw new InvalidConfigurationException(\'The node created by "NAME()" has already been initialized. You cannot pass values the second time you call NAME().\'); } return $this->PROPERTY; }' : ' COMMENTpublic function NAME(array $value = []): CLASS { if (null === $this->PROPERTY) { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY = new CLASS($value); } elseif (0 < \\func_num_args()) { throw new InvalidConfigurationException(\'The node created by "NAME()" has already been initialized. You cannot pass values the second time you call NAME().\'); } return $this->PROPERTY; }'; $class->addUse(InvalidConfigurationException::class); $class->addMethod($node->getName(), $body, ['COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn(), 'PARAM_TYPE' => \in_array('mixed', $nodeTypes, \true) ? 'mixed' : \implode('|', $nodeTypes)]); $this->buildNode($node, $childClass, $this->getSubNamespace($childClass)); } private function handleVariableNode(VariableNode $node, ClassBuilder $class) : void { $comment = $this->getComment($node); $property = $class->addProperty($node->getName()); $class->addUse(ParamConfigurator::class); $body = ' /** COMMENT * * @return $this */ public function NAME(mixed $valueDEFAULT): static { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY = $value; return $this; }'; $class->addMethod($node->getName(), $body, ['PROPERTY' => $property->getName(), 'COMMENT' => $comment, 'DEFAULT' => $node->hasDefaultValue() ? ' = ' . \var_export($node->getDefaultValue(), \true) : '']); } private function handlePrototypedArrayNode(PrototypedArrayNode $node, ClassBuilder $class, string $namespace) : void { $name = $this->getSingularName($node); $prototype = $node->getPrototype(); $methodName = $name; $hasNormalizationClosures = $this->hasNormalizationClosures($node) || $this->hasNormalizationClosures($prototype); $nodeParameterTypes = $this->getParameterTypes($node); $prototypeParameterTypes = $this->getParameterTypes($prototype); if (!$prototype instanceof ArrayNode || $prototype instanceof PrototypedArrayNode && $prototype->getPrototype() instanceof ScalarNode) { $class->addUse(ParamConfigurator::class); $property = $class->addProperty($node->getName()); if (null === ($key = $node->getKeyAttribute())) { // This is an array of values; don't use singular name $nodeTypesWithoutArray = \array_filter($nodeParameterTypes, static function ($type) { return 'array' !== $type; }); $body = ' /** * @param ParamConfigurator|list<ParamConfigurator|PROTOTYPE_TYPE>EXTRA_TYPE $value * * @return $this */ public function NAME(PARAM_TYPE $value): static { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY = $value; return $this; }'; $class->addMethod($node->getName(), $body, ['PROPERTY' => $property->getName(), 'PROTOTYPE_TYPE' => \implode('|', $prototypeParameterTypes), 'EXTRA_TYPE' => $nodeTypesWithoutArray ? '|' . \implode('|', $nodeTypesWithoutArray) : '', 'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, \true) ? 'mixed' : 'ParamConfigurator|' . \implode('|', $nodeParameterTypes)]); } else { $body = ' /** * @return $this */ public function NAME(string $VAR, TYPE $VALUE): static { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY[$VAR] = $VALUE; return $this; }'; $class->addMethod($methodName, $body, ['PROPERTY' => $property->getName(), 'TYPE' => \in_array('mixed', $prototypeParameterTypes, \true) ? 'mixed' : 'ParamConfigurator|' . \implode('|', $prototypeParameterTypes), 'VAR' => '' === $key ? 'key' : $key, 'VALUE' => 'value' === $key ? 'data' : 'value']); } return; } $childClass = new ClassBuilder($namespace, $name); if ($prototype instanceof ArrayNode) { $childClass->setAllowExtraKeys($prototype->shouldIgnoreExtraKeys()); } $class->addRequire($childClass); $this->classes[] = $childClass; $property = $class->addProperty($node->getName(), $this->getType($childClass->getFqcn() . '[]', $hasNormalizationClosures)); $comment = $this->getComment($node); if ($hasNormalizationClosures) { $comment = \sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment); $comment .= \sprintf(' * @return %s|$this' . "\n", $childClass->getFqcn()); $comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)' . "\n ", $childClass->getFqcn()); } if ('' !== $comment) { $comment = "/**\n{$comment}*/\n"; } if (null === ($key = $node->getKeyAttribute())) { $body = $hasNormalizationClosures ? ' COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static { $this->_usedProperties[\'PROPERTY\'] = true; if (!\\is_array($value)) { $this->PROPERTY[] = $value; return $this; } return $this->PROPERTY[] = new CLASS($value); }' : ' COMMENTpublic function NAME(array $value = []): CLASS { $this->_usedProperties[\'PROPERTY\'] = true; return $this->PROPERTY[] = new CLASS($value); }'; $class->addMethod($methodName, $body, ['COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn(), 'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, \true) ? 'mixed' : \implode('|', $nodeParameterTypes)]); } else { $body = $hasNormalizationClosures ? ' COMMENTpublic function NAME(string $VAR, PARAM_TYPE $VALUE = []): CLASS|static { if (!\\is_array($VALUE)) { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY[$VAR] = $VALUE; return $this; } if (!isset($this->PROPERTY[$VAR]) || !$this->PROPERTY[$VAR] instanceof CLASS) { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY[$VAR] = new CLASS($VALUE); } elseif (1 < \\func_num_args()) { throw new InvalidConfigurationException(\'The node created by "NAME()" has already been initialized. You cannot pass values the second time you call NAME().\'); } return $this->PROPERTY[$VAR]; }' : ' COMMENTpublic function NAME(string $VAR, array $VALUE = []): CLASS { if (!isset($this->PROPERTY[$VAR])) { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY[$VAR] = new CLASS($VALUE); } elseif (1 < \\func_num_args()) { throw new InvalidConfigurationException(\'The node created by "NAME()" has already been initialized. You cannot pass values the second time you call NAME().\'); } return $this->PROPERTY[$VAR]; }'; $class->addUse(InvalidConfigurationException::class); $class->addMethod($methodName, \str_replace('$value', '$VAR', $body), ['COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn(), 'VAR' => '' === $key ? 'key' : $key, 'VALUE' => 'value' === $key ? 'data' : 'value', 'PARAM_TYPE' => \in_array('mixed', $prototypeParameterTypes, \true) ? 'mixed' : \implode('|', $prototypeParameterTypes)]); } $this->buildNode($prototype, $childClass, $namespace . '\\' . $childClass->getName()); } private function handleScalarNode(ScalarNode $node, ClassBuilder $class) : void { $comment = $this->getComment($node); $property = $class->addProperty($node->getName()); $class->addUse(ParamConfigurator::class); $body = ' /** COMMENT * @return $this */ public function NAME($value): static { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY = $value; return $this; }'; $class->addMethod($node->getName(), $body, ['PROPERTY' => $property->getName(), 'COMMENT' => $comment]); } private function getParameterTypes(NodeInterface $node) : array { $paramTypes = []; if ($node instanceof BaseNode) { $types = $node->getNormalizedTypes(); if (\in_array(ExprBuilder::TYPE_ANY, $types, \true)) { $paramTypes[] = 'mixed'; } if (\in_array(ExprBuilder::TYPE_STRING, $types, \true)) { $paramTypes[] = 'string'; } } if ($node instanceof BooleanNode) { $paramTypes[] = 'bool'; } elseif ($node instanceof IntegerNode) { $paramTypes[] = 'int'; } elseif ($node instanceof FloatNode) { $paramTypes[] = 'float'; } elseif ($node instanceof EnumNode) { $paramTypes[] = 'mixed'; } elseif ($node instanceof ArrayNode) { $paramTypes[] = 'array'; } elseif ($node instanceof VariableNode) { $paramTypes[] = 'mixed'; } return \array_unique($paramTypes); } private function getComment(BaseNode $node) : string { $comment = ''; if ('' !== ($info = (string) $node->getInfo())) { $comment .= ' * ' . $info . "\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 ($node instanceof EnumNode) { $comment .= \sprintf(' * @param ParamConfigurator|%s $value', \implode('|', \array_unique(\array_map(function ($a) { return !$a instanceof \UnitEnum ? \var_export($a, \true) : '\\' . \ltrim(\var_export($a, \true), '\\'); }, $node->getValues())))) . "\n"; } else { $parameterTypes = $this->getParameterTypes($node); $comment .= ' * @param ParamConfigurator|' . \implode('|', $parameterTypes) . ' $value' . "\n"; } } else { foreach ((array) ($node->getExample() ?? []) as $example) { $comment .= ' * @example ' . \json_encode($example) . "\n"; } if ($node->hasDefaultValue() && [] != ($default = $node->getDefaultValue())) { $comment .= ' * @default ' . \json_encode($default) . "\n"; } } if ($node->isDeprecated()) { $comment .= ' * @deprecated ' . $node->getDeprecation($node->getName(), $node->getParent()->getName())['message'] . "\n"; } return $comment; } /** * Pick a good singular name. */ private function getSingularName(PrototypedArrayNode $node) : string { $name = $node->getName(); if (\substr_compare($name, 's', -\strlen('s')) !== 0) { return $name; } $parent = $node->getParent(); $mappings = $parent instanceof ArrayNode ? $parent->getXmlRemappings() : []; foreach ($mappings as $map) { if ($map[1] === $name) { $name = $map[0]; break; } } return $name; } private function buildToArray(ClassBuilder $class) : void { $body = '$output = [];'; foreach ($class->getProperties() as $p) { $code = '$this->PROPERTY'; if (null !== $p->getType()) { if ($p->isArray()) { $code = $p->areScalarsAllowed() ? 'array_map(function ($v) { return $v instanceof CLASS ? $v->toArray() : $v; }, $this->PROPERTY)' : 'array_map(function ($v) { return $v->toArray(); }, $this->PROPERTY)'; } else { $code = $p->areScalarsAllowed() ? '$this->PROPERTY instanceof CLASS ? $this->PROPERTY->toArray() : $this->PROPERTY' : '$this->PROPERTY->toArray()'; } } $body .= \strtr(' if (isset($this->_usedProperties[\'PROPERTY\'])) { $output[\'ORG_NAME\'] = ' . $code . '; }', ['PROPERTY' => $p->getName(), 'ORG_NAME' => $p->getOriginalName(), 'CLASS' => $p->getType()]); } $extraKeys = $class->shouldAllowExtraKeys() ? ' + $this->_extraKeys' : ''; $class->addMethod('toArray', ' public function NAME(): array { ' . $body . ' return $output' . $extraKeys . '; }'); } private function buildConstructor(ClassBuilder $class) : void { $body = ''; foreach ($class->getProperties() as $p) { $code = '$value[\'ORG_NAME\']'; if (null !== $p->getType()) { if ($p->isArray()) { $code = $p->areScalarsAllowed() ? 'array_map(function ($v) { return \\is_array($v) ? new ' . $p->getType() . '($v) : $v; }, $value[\'ORG_NAME\'])' : 'array_map(function ($v) { return new ' . $p->getType() . '($v); }, $value[\'ORG_NAME\'])'; } else { $code = $p->areScalarsAllowed() ? '\\is_array($value[\'ORG_NAME\']) ? new ' . $p->getType() . '($value[\'ORG_NAME\']) : $value[\'ORG_NAME\']' : 'new ' . $p->getType() . '($value[\'ORG_NAME\'])'; } } $body .= \strtr(' if (array_key_exists(\'ORG_NAME\', $value)) { $this->_usedProperties[\'PROPERTY\'] = true; $this->PROPERTY = ' . $code . '; unset($value[\'ORG_NAME\']); } ', ['PROPERTY' => $p->getName(), 'ORG_NAME' => $p->getOriginalName()]); } if ($class->shouldAllowExtraKeys()) { $body .= ' $this->_extraKeys = $value; '; } else { $body .= ' if ([] !== $value) { throw new InvalidConfigurationException(sprintf(\'The following keys are not supported by "%s": \', __CLASS__).implode(\', \', array_keys($value))); }'; $class->addUse(InvalidConfigurationException::class); } $class->addMethod('__construct', ' public function __construct(array $value = []) {' . $body . ' }'); } private function buildSetExtraKey(ClassBuilder $class) : void { if (!$class->shouldAllowExtraKeys()) { return; } $class->addUse(ParamConfigurator::class); $class->addProperty('_extraKeys'); $class->addMethod('set', ' /** * @param ParamConfigurator|mixed $value * * @return $this */ public function NAME(string $key, mixed $value): static { $this->_extraKeys[$key] = $value; return $this; }'); } private function getSubNamespace(ClassBuilder $rootClass) : string { return \sprintf('%s\\%s', $rootClass->getNamespace(), \substr($rootClass->getName(), 0, -6)); } private function hasNormalizationClosures(NodeInterface $node) : bool { try { $r = new \ReflectionProperty($node, 'normalizationClosures'); $r->setAccessible(\true); } catch (\ReflectionException $exception) { return \false; } $r->setAccessible(\true); return [] !== $r->getValue($node); } private function getType(string $classType, bool $hasNormalizationClosures) : string { return $classType . ($hasNormalizationClosures ? '|scalar' : ''); } }