| Total Complexity | 88 |
| Total Lines | 564 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like ConfigBuilderGenerator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use ConfigBuilderGenerator, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 34 | class ConfigBuilderGenerator implements ConfigBuilderGeneratorInterface |
||
| 35 | { |
||
| 36 | /** |
||
| 37 | * @var ClassBuilder[] |
||
| 38 | */ |
||
| 39 | private array $classes = []; |
||
| 40 | |||
| 41 | public function __construct( |
||
| 42 | private string $outputDir, |
||
| 43 | ) { |
||
| 44 | } |
||
| 45 | |||
| 46 | /** |
||
| 47 | * @return \Closure that will return the root config class |
||
| 48 | */ |
||
| 49 | public function build(ConfigurationInterface $configuration): \Closure |
||
| 50 | { |
||
| 51 | $this->classes = []; |
||
| 52 | |||
| 53 | $rootNode = $configuration->getConfigTreeBuilder()->buildTree(); |
||
| 54 | $rootClass = new ClassBuilder('Symfony\\Config', $rootNode->getName()); |
||
| 55 | |||
| 56 | $path = $this->getFullPath($rootClass); |
||
| 57 | if (!is_file($path)) { |
||
| 58 | // Generate the class if the file not exists |
||
| 59 | $this->classes[] = $rootClass; |
||
| 60 | $this->buildNode($rootNode, $rootClass, $this->getSubNamespace($rootClass)); |
||
| 61 | $rootClass->addImplements(ConfigBuilderInterface::class); |
||
| 62 | $rootClass->addMethod('getExtensionAlias', ' |
||
| 63 | public function NAME(): string |
||
| 64 | { |
||
| 65 | return \'ALIAS\'; |
||
| 66 | }', ['ALIAS' => $rootNode->getPath()]); |
||
| 67 | |||
| 68 | $this->writeClasses(); |
||
| 69 | } |
||
| 70 | |||
| 71 | return function () use ($path, $rootClass) { |
||
| 72 | require_once $path; |
||
| 73 | $className = $rootClass->getFqcn(); |
||
| 74 | |||
| 75 | return new $className(); |
||
| 76 | }; |
||
| 77 | } |
||
| 78 | |||
| 79 | private function getFullPath(ClassBuilder $class): string |
||
| 80 | { |
||
| 81 | $directory = $this->outputDir.\DIRECTORY_SEPARATOR.$class->getDirectory(); |
||
| 82 | if (!is_dir($directory)) { |
||
| 83 | @mkdir($directory, 0777, true); |
||
|
|
|||
| 84 | } |
||
| 85 | |||
| 86 | return $directory.\DIRECTORY_SEPARATOR.$class->getFilename(); |
||
| 87 | } |
||
| 88 | |||
| 89 | private function writeClasses(): void |
||
| 90 | { |
||
| 91 | foreach ($this->classes as $class) { |
||
| 92 | $this->buildConstructor($class); |
||
| 93 | $this->buildToArray($class); |
||
| 94 | if ($class->getProperties()) { |
||
| 95 | $class->addProperty('_usedProperties', null, '[]'); |
||
| 96 | } |
||
| 97 | $this->buildSetExtraKey($class); |
||
| 98 | |||
| 99 | file_put_contents($this->getFullPath($class), $class->build()); |
||
| 100 | } |
||
| 101 | |||
| 102 | $this->classes = []; |
||
| 103 | } |
||
| 104 | |||
| 105 | private function buildNode(NodeInterface $node, ClassBuilder $class, string $namespace): void |
||
| 106 | { |
||
| 107 | if (!$node instanceof ArrayNode) { |
||
| 108 | throw new \LogicException('The node was expected to be an ArrayNode. This Configuration includes an edge case not supported yet.'); |
||
| 109 | } |
||
| 110 | |||
| 111 | foreach ($node->getChildren() as $child) { |
||
| 112 | match (true) { |
||
| 113 | $child instanceof ScalarNode => $this->handleScalarNode($child, $class), |
||
| 114 | $child instanceof PrototypedArrayNode => $this->handlePrototypedArrayNode($child, $class, $namespace), |
||
| 115 | $child instanceof VariableNode => $this->handleVariableNode($child, $class), |
||
| 116 | $child instanceof ArrayNode => $this->handleArrayNode($child, $class, $namespace), |
||
| 117 | default => throw new \RuntimeException(\sprintf('Unknown node "%s".', $child::class)), |
||
| 118 | }; |
||
| 119 | } |
||
| 120 | } |
||
| 121 | |||
| 122 | private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $namespace): void |
||
| 123 | { |
||
| 124 | $childClass = new ClassBuilder($namespace, $node->getName()); |
||
| 125 | $childClass->setAllowExtraKeys($node->shouldIgnoreExtraKeys()); |
||
| 126 | $class->addRequire($childClass); |
||
| 127 | $this->classes[] = $childClass; |
||
| 128 | |||
| 129 | $hasNormalizationClosures = $this->hasNormalizationClosures($node); |
||
| 130 | $comment = $this->getComment($node); |
||
| 131 | if ($hasNormalizationClosures) { |
||
| 132 | $comment = \sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment); |
||
| 133 | $comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn()); |
||
| 134 | $comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn()); |
||
| 135 | } |
||
| 136 | if ('' !== $comment) { |
||
| 137 | $comment = "/**\n$comment*/\n"; |
||
| 138 | } |
||
| 139 | |||
| 140 | $property = $class->addProperty( |
||
| 141 | $node->getName(), |
||
| 142 | $this->getType($childClass->getFqcn(), $hasNormalizationClosures) |
||
| 143 | ); |
||
| 144 | $nodeTypes = $this->getParameterTypes($node); |
||
| 145 | $body = $hasNormalizationClosures ? ' |
||
| 146 | COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static |
||
| 147 | { |
||
| 148 | if (!\is_array($value)) { |
||
| 149 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 150 | $this->PROPERTY = $value; |
||
| 151 | |||
| 152 | return $this; |
||
| 153 | } |
||
| 154 | |||
| 155 | if (!$this->PROPERTY instanceof CLASS) { |
||
| 156 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 157 | $this->PROPERTY = new CLASS($value); |
||
| 158 | } elseif (0 < \func_num_args()) { |
||
| 159 | throw new InvalidConfigurationException(\'The node created by "NAME()" has already been initialized. You cannot pass values the second time you call NAME().\'); |
||
| 160 | } |
||
| 161 | |||
| 162 | return $this->PROPERTY; |
||
| 163 | }' : ' |
||
| 164 | COMMENTpublic function NAME(array $value = []): CLASS |
||
| 165 | { |
||
| 166 | if (null === $this->PROPERTY) { |
||
| 167 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 168 | $this->PROPERTY = new CLASS($value); |
||
| 169 | } elseif (0 < \func_num_args()) { |
||
| 170 | throw new InvalidConfigurationException(\'The node created by "NAME()" has already been initialized. You cannot pass values the second time you call NAME().\'); |
||
| 171 | } |
||
| 172 | |||
| 173 | return $this->PROPERTY; |
||
| 174 | }'; |
||
| 175 | $class->addUse(InvalidConfigurationException::class); |
||
| 176 | $class->addMethod($node->getName(), $body, [ |
||
| 177 | 'COMMENT' => $comment, |
||
| 178 | 'PROPERTY' => $property->getName(), |
||
| 179 | 'CLASS' => $childClass->getFqcn(), |
||
| 180 | 'PARAM_TYPE' => \in_array('mixed', $nodeTypes, true) ? 'mixed' : implode('|', $nodeTypes), |
||
| 181 | ]); |
||
| 182 | |||
| 183 | $this->buildNode($node, $childClass, $this->getSubNamespace($childClass)); |
||
| 184 | } |
||
| 185 | |||
| 186 | private function handleVariableNode(VariableNode $node, ClassBuilder $class): void |
||
| 187 | { |
||
| 188 | $comment = $this->getComment($node); |
||
| 189 | $property = $class->addProperty($node->getName()); |
||
| 190 | $class->addUse(ParamConfigurator::class); |
||
| 191 | |||
| 192 | $body = ' |
||
| 193 | /** |
||
| 194 | COMMENT * |
||
| 195 | * @return $this |
||
| 196 | */ |
||
| 197 | public function NAME(mixed $valueDEFAULT): static |
||
| 198 | { |
||
| 199 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 200 | $this->PROPERTY = $value; |
||
| 201 | |||
| 202 | return $this; |
||
| 203 | }'; |
||
| 204 | $class->addMethod($node->getName(), $body, [ |
||
| 205 | 'PROPERTY' => $property->getName(), |
||
| 206 | 'COMMENT' => $comment, |
||
| 207 | 'DEFAULT' => $node->hasDefaultValue() ? ' = '.var_export($node->getDefaultValue(), true) : '', |
||
| 208 | ]); |
||
| 209 | } |
||
| 210 | |||
| 211 | private function handlePrototypedArrayNode(PrototypedArrayNode $node, ClassBuilder $class, string $namespace): void |
||
| 212 | { |
||
| 213 | $name = $this->getSingularName($node); |
||
| 214 | $prototype = $node->getPrototype(); |
||
| 215 | $methodName = $name; |
||
| 216 | $hasNormalizationClosures = $this->hasNormalizationClosures($node) || $this->hasNormalizationClosures($prototype); |
||
| 217 | |||
| 218 | $nodeParameterTypes = $this->getParameterTypes($node); |
||
| 219 | $prototypeParameterTypes = $this->getParameterTypes($prototype); |
||
| 220 | if (!$prototype instanceof ArrayNode || ($prototype instanceof PrototypedArrayNode && $prototype->getPrototype() instanceof ScalarNode)) { |
||
| 221 | $class->addUse(ParamConfigurator::class); |
||
| 222 | $property = $class->addProperty($node->getName()); |
||
| 223 | if (null === $key = $node->getKeyAttribute()) { |
||
| 224 | // This is an array of values; don't use singular name |
||
| 225 | $nodeTypesWithoutArray = array_filter($nodeParameterTypes, static fn ($type) => 'array' !== $type); |
||
| 226 | $body = ' |
||
| 227 | /** |
||
| 228 | * @param ParamConfigurator|list<ParamConfigurator|PROTOTYPE_TYPE>EXTRA_TYPE $value |
||
| 229 | * |
||
| 230 | * @return $this |
||
| 231 | */ |
||
| 232 | public function NAME(PARAM_TYPE $value): static |
||
| 233 | { |
||
| 234 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 235 | $this->PROPERTY = $value; |
||
| 236 | |||
| 237 | return $this; |
||
| 238 | }'; |
||
| 239 | |||
| 240 | $class->addMethod($node->getName(), $body, [ |
||
| 241 | 'PROPERTY' => $property->getName(), |
||
| 242 | 'PROTOTYPE_TYPE' => implode('|', $prototypeParameterTypes), |
||
| 243 | 'EXTRA_TYPE' => $nodeTypesWithoutArray ? '|'.implode('|', $nodeTypesWithoutArray) : '', |
||
| 244 | 'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $nodeParameterTypes), |
||
| 245 | ]); |
||
| 246 | } else { |
||
| 247 | $body = ' |
||
| 248 | /** |
||
| 249 | * @return $this |
||
| 250 | */ |
||
| 251 | public function NAME(string $VAR, TYPE $VALUE): static |
||
| 252 | { |
||
| 253 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 254 | $this->PROPERTY[$VAR] = $VALUE; |
||
| 255 | |||
| 256 | return $this; |
||
| 257 | }'; |
||
| 258 | |||
| 259 | $class->addMethod($methodName, $body, [ |
||
| 260 | 'PROPERTY' => $property->getName(), |
||
| 261 | 'TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $prototypeParameterTypes), |
||
| 262 | 'VAR' => '' === $key ? 'key' : $key, |
||
| 263 | 'VALUE' => 'value' === $key ? 'data' : 'value', |
||
| 264 | ]); |
||
| 265 | } |
||
| 266 | |||
| 267 | return; |
||
| 268 | } |
||
| 269 | |||
| 270 | $childClass = new ClassBuilder($namespace, $name); |
||
| 271 | if ($prototype instanceof ArrayNode) { |
||
| 272 | $childClass->setAllowExtraKeys($prototype->shouldIgnoreExtraKeys()); |
||
| 273 | } |
||
| 274 | $class->addRequire($childClass); |
||
| 275 | $this->classes[] = $childClass; |
||
| 276 | |||
| 277 | $property = $class->addProperty( |
||
| 278 | $node->getName(), |
||
| 279 | $this->getType($childClass->getFqcn().'[]', $hasNormalizationClosures) |
||
| 280 | ); |
||
| 281 | |||
| 282 | $comment = $this->getComment($node); |
||
| 283 | if ($hasNormalizationClosures) { |
||
| 284 | $comment = \sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment); |
||
| 285 | $comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn()); |
||
| 286 | $comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn()); |
||
| 287 | } |
||
| 288 | if ('' !== $comment) { |
||
| 289 | $comment = "/**\n$comment*/\n"; |
||
| 290 | } |
||
| 291 | |||
| 292 | if (null === $key = $node->getKeyAttribute()) { |
||
| 293 | $body = $hasNormalizationClosures ? ' |
||
| 294 | COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static |
||
| 295 | { |
||
| 296 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 297 | if (!\is_array($value)) { |
||
| 298 | $this->PROPERTY[] = $value; |
||
| 299 | |||
| 300 | return $this; |
||
| 301 | } |
||
| 302 | |||
| 303 | return $this->PROPERTY[] = new CLASS($value); |
||
| 304 | }' : ' |
||
| 305 | COMMENTpublic function NAME(array $value = []): CLASS |
||
| 306 | { |
||
| 307 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 308 | |||
| 309 | return $this->PROPERTY[] = new CLASS($value); |
||
| 310 | }'; |
||
| 311 | $class->addMethod($methodName, $body, [ |
||
| 312 | 'COMMENT' => $comment, |
||
| 313 | 'PROPERTY' => $property->getName(), |
||
| 314 | 'CLASS' => $childClass->getFqcn(), |
||
| 315 | 'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : implode('|', $nodeParameterTypes), |
||
| 316 | ]); |
||
| 317 | } else { |
||
| 318 | $body = $hasNormalizationClosures ? ' |
||
| 319 | COMMENTpublic function NAME(string $VAR, PARAM_TYPE $VALUE = []): CLASS|static |
||
| 320 | { |
||
| 321 | if (!\is_array($VALUE)) { |
||
| 322 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 323 | $this->PROPERTY[$VAR] = $VALUE; |
||
| 324 | |||
| 325 | return $this; |
||
| 326 | } |
||
| 327 | |||
| 328 | if (!isset($this->PROPERTY[$VAR]) || !$this->PROPERTY[$VAR] instanceof CLASS) { |
||
| 329 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 330 | $this->PROPERTY[$VAR] = new CLASS($VALUE); |
||
| 331 | } elseif (1 < \func_num_args()) { |
||
| 332 | throw new InvalidConfigurationException(\'The node created by "NAME()" has already been initialized. You cannot pass values the second time you call NAME().\'); |
||
| 333 | } |
||
| 334 | |||
| 335 | return $this->PROPERTY[$VAR]; |
||
| 336 | }' : ' |
||
| 337 | COMMENTpublic function NAME(string $VAR, array $VALUE = []): CLASS |
||
| 338 | { |
||
| 339 | if (!isset($this->PROPERTY[$VAR])) { |
||
| 340 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 341 | $this->PROPERTY[$VAR] = new CLASS($VALUE); |
||
| 342 | } elseif (1 < \func_num_args()) { |
||
| 343 | throw new InvalidConfigurationException(\'The node created by "NAME()" has already been initialized. You cannot pass values the second time you call NAME().\'); |
||
| 344 | } |
||
| 345 | |||
| 346 | return $this->PROPERTY[$VAR]; |
||
| 347 | }'; |
||
| 348 | $class->addUse(InvalidConfigurationException::class); |
||
| 349 | $class->addMethod($methodName, str_replace('$value', '$VAR', $body), [ |
||
| 350 | 'COMMENT' => $comment, 'PROPERTY' => $property->getName(), |
||
| 351 | 'CLASS' => $childClass->getFqcn(), |
||
| 352 | 'VAR' => '' === $key ? 'key' : $key, |
||
| 353 | 'VALUE' => 'value' === $key ? 'data' : 'value', |
||
| 354 | 'PARAM_TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : implode('|', $prototypeParameterTypes), |
||
| 355 | ]); |
||
| 356 | } |
||
| 357 | |||
| 358 | $this->buildNode($prototype, $childClass, $namespace.'\\'.$childClass->getName()); |
||
| 359 | } |
||
| 360 | |||
| 361 | private function handleScalarNode(ScalarNode $node, ClassBuilder $class): void |
||
| 362 | { |
||
| 363 | $comment = $this->getComment($node); |
||
| 364 | $property = $class->addProperty($node->getName()); |
||
| 365 | $class->addUse(ParamConfigurator::class); |
||
| 366 | |||
| 367 | $body = ' |
||
| 368 | /** |
||
| 369 | COMMENT * @return $this |
||
| 370 | */ |
||
| 371 | public function NAME($value): static |
||
| 372 | { |
||
| 373 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 374 | $this->PROPERTY = $value; |
||
| 375 | |||
| 376 | return $this; |
||
| 377 | }'; |
||
| 378 | |||
| 379 | $class->addMethod($node->getName(), $body, ['PROPERTY' => $property->getName(), 'COMMENT' => $comment]); |
||
| 380 | } |
||
| 381 | |||
| 382 | private function getParameterTypes(NodeInterface $node): array |
||
| 383 | { |
||
| 384 | $paramTypes = []; |
||
| 385 | if ($node instanceof BaseNode) { |
||
| 386 | $types = $node->getNormalizedTypes(); |
||
| 387 | if (\in_array(ExprBuilder::TYPE_ANY, $types, true)) { |
||
| 388 | $paramTypes[] = 'mixed'; |
||
| 389 | } |
||
| 390 | if (\in_array(ExprBuilder::TYPE_STRING, $types, true)) { |
||
| 391 | $paramTypes[] = 'string'; |
||
| 392 | } |
||
| 393 | } |
||
| 394 | if ($node instanceof BooleanNode) { |
||
| 395 | $paramTypes[] = 'bool'; |
||
| 396 | } elseif ($node instanceof IntegerNode) { |
||
| 397 | $paramTypes[] = 'int'; |
||
| 398 | } elseif ($node instanceof FloatNode) { |
||
| 399 | $paramTypes[] = 'float'; |
||
| 400 | } elseif ($node instanceof EnumNode) { |
||
| 401 | $paramTypes[] = 'mixed'; |
||
| 402 | } elseif ($node instanceof ArrayNode) { |
||
| 403 | $paramTypes[] = 'array'; |
||
| 404 | } elseif ($node instanceof VariableNode) { |
||
| 405 | $paramTypes[] = 'mixed'; |
||
| 406 | } |
||
| 407 | |||
| 408 | return array_unique($paramTypes); |
||
| 409 | } |
||
| 410 | |||
| 411 | private function getComment(BaseNode $node): string |
||
| 412 | { |
||
| 413 | $comment = ''; |
||
| 414 | if ('' !== $info = (string) $node->getInfo()) { |
||
| 415 | $comment .= ' * '.$info."\n"; |
||
| 416 | } |
||
| 417 | |||
| 418 | if (!$node instanceof ArrayNode) { |
||
| 419 | foreach ((array) ($node->getExample() ?? []) as $example) { |
||
| 420 | $comment .= ' * @example '.$example."\n"; |
||
| 421 | } |
||
| 422 | |||
| 423 | if ('' !== $default = $node->getDefaultValue()) { |
||
| 424 | $comment .= ' * @default '.(null === $default ? 'null' : var_export($default, true))."\n"; |
||
| 425 | } |
||
| 426 | |||
| 427 | if ($node instanceof EnumNode) { |
||
| 428 | $comment .= \sprintf(' * @param ParamConfigurator|%s $value', implode('|', array_unique(array_map(fn ($a) => !$a instanceof \UnitEnum ? var_export($a, true) : '\\'.ltrim(var_export($a, true), '\\'), $node->getValues()))))."\n"; |
||
| 429 | } else { |
||
| 430 | $parameterTypes = $this->getParameterTypes($node); |
||
| 431 | $comment .= ' * @param ParamConfigurator|'.implode('|', $parameterTypes).' $value'."\n"; |
||
| 432 | } |
||
| 433 | } else { |
||
| 434 | foreach ((array) ($node->getExample() ?? []) as $example) { |
||
| 435 | $comment .= ' * @example '.json_encode($example)."\n"; |
||
| 436 | } |
||
| 437 | |||
| 438 | if ($node->hasDefaultValue() && [] != $default = $node->getDefaultValue()) { |
||
| 439 | $comment .= ' * @default '.json_encode($default)."\n"; |
||
| 440 | } |
||
| 441 | } |
||
| 442 | |||
| 443 | if ($node->isDeprecated()) { |
||
| 444 | $comment .= ' * @deprecated '.$node->getDeprecation($node->getName(), $node->getParent()->getName())['message']."\n"; |
||
| 445 | } |
||
| 446 | |||
| 447 | return $comment; |
||
| 448 | } |
||
| 449 | |||
| 450 | /** |
||
| 451 | * Pick a good singular name. |
||
| 452 | */ |
||
| 453 | private function getSingularName(PrototypedArrayNode $node): string |
||
| 454 | { |
||
| 455 | $name = $node->getName(); |
||
| 456 | if (!str_ends_with($name, 's')) { |
||
| 457 | return $name; |
||
| 458 | } |
||
| 459 | |||
| 460 | $parent = $node->getParent(); |
||
| 461 | $mappings = $parent instanceof ArrayNode ? $parent->getXmlRemappings() : []; |
||
| 462 | foreach ($mappings as $map) { |
||
| 463 | if ($map[1] === $name) { |
||
| 464 | $name = $map[0]; |
||
| 465 | break; |
||
| 466 | } |
||
| 467 | } |
||
| 468 | |||
| 469 | return $name; |
||
| 470 | } |
||
| 471 | |||
| 472 | private function buildToArray(ClassBuilder $class): void |
||
| 505 | }'); |
||
| 506 | } |
||
| 507 | |||
| 508 | private function buildConstructor(ClassBuilder $class): void |
||
| 509 | { |
||
| 510 | $body = ''; |
||
| 511 | foreach ($class->getProperties() as $p) { |
||
| 512 | $code = '$value[\'ORG_NAME\']'; |
||
| 513 | if (null !== $p->getType()) { |
||
| 514 | if ($p->isArray()) { |
||
| 515 | $code = $p->areScalarsAllowed() |
||
| 516 | ? 'array_map(fn ($v) => \is_array($v) ? new '.$p->getType().'($v) : $v, $value[\'ORG_NAME\'])' |
||
| 517 | : 'array_map(fn ($v) => new '.$p->getType().'($v), $value[\'ORG_NAME\'])' |
||
| 518 | ; |
||
| 519 | } else { |
||
| 520 | $code = $p->areScalarsAllowed() |
||
| 521 | ? '\is_array($value[\'ORG_NAME\']) ? new '.$p->getType().'($value[\'ORG_NAME\']) : $value[\'ORG_NAME\']' |
||
| 522 | : 'new '.$p->getType().'($value[\'ORG_NAME\'])' |
||
| 523 | ; |
||
| 524 | } |
||
| 525 | } |
||
| 526 | |||
| 527 | $body .= strtr(' |
||
| 528 | if (array_key_exists(\'ORG_NAME\', $value)) { |
||
| 529 | $this->_usedProperties[\'PROPERTY\'] = true; |
||
| 530 | $this->PROPERTY = '.$code.'; |
||
| 531 | unset($value[\'ORG_NAME\']); |
||
| 532 | } |
||
| 533 | ', ['PROPERTY' => $p->getName(), 'ORG_NAME' => $p->getOriginalName()]); |
||
| 534 | } |
||
| 535 | |||
| 536 | if ($class->shouldAllowExtraKeys()) { |
||
| 537 | $body .= ' |
||
| 538 | $this->_extraKeys = $value; |
||
| 539 | '; |
||
| 540 | } else { |
||
| 541 | $body .= ' |
||
| 542 | if ([] !== $value) { |
||
| 543 | throw new InvalidConfigurationException(sprintf(\'The following keys are not supported by "%s": \', __CLASS__).implode(\', \', array_keys($value))); |
||
| 544 | }'; |
||
| 545 | |||
| 546 | $class->addUse(InvalidConfigurationException::class); |
||
| 547 | } |
||
| 548 | |||
| 549 | $class->addMethod('__construct', ' |
||
| 550 | public function __construct(array $value = []) |
||
| 551 | {'.$body.' |
||
| 552 | }'); |
||
| 553 | } |
||
| 554 | |||
| 555 | private function buildSetExtraKey(ClassBuilder $class): void |
||
| 556 | { |
||
| 557 | if (!$class->shouldAllowExtraKeys()) { |
||
| 558 | return; |
||
| 559 | } |
||
| 560 | |||
| 561 | $class->addUse(ParamConfigurator::class); |
||
| 562 | |||
| 563 | $class->addProperty('_extraKeys'); |
||
| 564 | |||
| 565 | $class->addMethod('set', ' |
||
| 566 | /** |
||
| 567 | * @param ParamConfigurator|mixed $value |
||
| 568 | * |
||
| 569 | * @return $this |
||
| 570 | */ |
||
| 571 | public function NAME(string $key, mixed $value): static |
||
| 572 | { |
||
| 573 | $this->_extraKeys[$key] = $value; |
||
| 574 | |||
| 575 | return $this; |
||
| 576 | }'); |
||
| 577 | } |
||
| 578 | |||
| 579 | private function getSubNamespace(ClassBuilder $rootClass): string |
||
| 580 | { |
||
| 581 | return \sprintf('%s\\%s', $rootClass->getNamespace(), substr($rootClass->getName(), 0, -6)); |
||
| 582 | } |
||
| 583 | |||
| 584 | private function hasNormalizationClosures(NodeInterface $node): bool |
||
| 593 | } |
||
| 594 | |||
| 595 | private function getType(string $classType, bool $hasNormalizationClosures): string |
||
| 596 | { |
||
| 598 | } |
||
| 599 | } |
||
| 600 |
If you suppress an error, we recommend checking for the error condition explicitly: