From b6387575295c187eb67158872bf97eac3606d955 Mon Sep 17 00:00:00 2001 From: Vladislav Strelchenko <85889893+VladislavStrelchenko@users.noreply.github.com> Date: Tue, 28 Nov 2023 15:17:48 +0200 Subject: [PATCH] SDK-5377: Introduce array element to env manifeststrategy (#161) --- composer.json | 2 +- src/Builder/ClassBuilderFacade.php | 4 +- src/Builder/ClassGenerator/ClassGenerator.php | 2 +- src/Builder/ClassLoader/AbstractLoader.php | 53 ++ src/Builder/ClassLoader/ClassLoader.php | 45 +- src/Builder/ClassLoader/FileLoader.php | 43 + .../ClassLoader/FileLoaderInterface.php | 22 + .../ClassModifier/AddVisitorsTrait.php | 4 +- .../CommonClass/CommonClassModifier.php | 8 +- .../ConfigFile/ConfigFileModifier.php | 60 ++ .../ConfigFileModifierInterface.php | 24 + .../Unwire/UnwireGlueRelationshipModifier.php | 2 +- .../Wire/WireGlueRelationshipModifier.php | 2 +- .../ClassWriter/ClassFileWriterInterface.php | 22 - .../ArrayConfigurationEnvironmentStrategy.php | 15 +- src/Builder/Creator/MethodCreator.php | 2 +- .../Exception/ValueExtractorException.php | 16 + src/Builder/Extractor/ExpressionExtractor.php | 137 +++ .../ExpressionExtractorInterface.php | 22 + .../AbstractValueExtractorStrategy.php | 113 +++ .../ValueExtractor/ArrayDimValueExtractor.php | 49 ++ .../ArrayValueExtractorStrategy.php | 62 ++ .../ValueExtractor/CastValueExtractor.php | 73 ++ .../ClassConstFetchValueExtractorStrategy.php | 44 + .../ConcatValueExtractorStrategy.php | 44 + .../ConstFetchValueExtractorStrategy.php | 62 ++ .../DefaultIsLiteralExtractorStrategy.php | 43 + .../FloatValueExtractorStrategy.php | 40 + .../ValueExtractor/FuncCallValueExtractor.php | 73 ++ .../IntegerValueExtractorStrategy.php | 40 + .../MethodCallExtractorStrategy.php | 26 + .../StringValueExtractorStrategy.php | 40 + .../TernaryValueExtractorStrategy.php | 53 ++ .../ValueExtractorStrategyCollection.php | 79 ++ .../ValueExtractorStrategyInterface.php | 34 + .../VariableExtractorStrategy.php | 40 + src/Builder/FileBuilderFacade.php | 42 + src/Builder/FileBuilderFacadeInterface.php | 29 + .../FileWriter.php} | 18 +- .../FileWriter/FileWriterInterface.php | 22 + src/Builder/Finder/ClassNodeFinder.php | 8 +- src/Builder/Printer/ClassDiffPrinter.php | 12 +- .../AddArrayItemToEnvConfigVisitor.php | 114 +++ .../AddPluginToPluginCollectionVisitor.php | 4 +- src/IntegratorFactory.php | 70 +- .../ConfigureEnvManifestStrategy.php | 121 ++- src/Transfer/ChainAssignValueTransfer.php | 61 ++ src/Transfer/ClassInformationTransfer.php | 795 +----------------- src/Transfer/ExtractedValueTransfer.php | 64 ++ src/Transfer/FileInformationTransfer.php | 172 ++++ .../Integrator/BaseTestCase.php | 4 +- .../Builder/ClassLoader/ClassLoaderTest.php | 2 +- 52 files changed, 2028 insertions(+), 910 deletions(-) create mode 100644 src/Builder/ClassLoader/AbstractLoader.php create mode 100644 src/Builder/ClassLoader/FileLoader.php create mode 100644 src/Builder/ClassLoader/FileLoaderInterface.php create mode 100644 src/Builder/ClassModifier/ConfigFile/ConfigFileModifier.php create mode 100644 src/Builder/ClassModifier/ConfigFile/ConfigFileModifierInterface.php delete mode 100644 src/Builder/ClassWriter/ClassFileWriterInterface.php create mode 100644 src/Builder/Exception/ValueExtractorException.php create mode 100644 src/Builder/Extractor/ExpressionExtractor.php create mode 100644 src/Builder/Extractor/ExpressionExtractorInterface.php create mode 100644 src/Builder/Extractor/ValueExtractor/AbstractValueExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/ArrayDimValueExtractor.php create mode 100644 src/Builder/Extractor/ValueExtractor/ArrayValueExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/CastValueExtractor.php create mode 100644 src/Builder/Extractor/ValueExtractor/ClassConstFetchValueExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/ConcatValueExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/ConstFetchValueExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/DefaultIsLiteralExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/FloatValueExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/FuncCallValueExtractor.php create mode 100644 src/Builder/Extractor/ValueExtractor/IntegerValueExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/MethodCallExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/StringValueExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/TernaryValueExtractorStrategy.php create mode 100644 src/Builder/Extractor/ValueExtractor/ValueExtractorStrategyCollection.php create mode 100644 src/Builder/Extractor/ValueExtractor/ValueExtractorStrategyInterface.php create mode 100644 src/Builder/Extractor/ValueExtractor/VariableExtractorStrategy.php create mode 100644 src/Builder/FileBuilderFacade.php create mode 100644 src/Builder/FileBuilderFacadeInterface.php rename src/Builder/{ClassWriter/ClassFileWriter.php => FileWriter/FileWriter.php} (74%) create mode 100644 src/Builder/FileWriter/FileWriterInterface.php create mode 100644 src/Builder/Visitor/AddArrayItemToEnvConfigVisitor.php create mode 100644 src/Transfer/ChainAssignValueTransfer.php create mode 100644 src/Transfer/ExtractedValueTransfer.php create mode 100644 src/Transfer/FileInformationTransfer.php diff --git a/composer.json b/composer.json index 92c1b65b..fd732a9f 100644 --- a/composer.json +++ b/composer.json @@ -8,8 +8,8 @@ "ext-dom": "*", "ext-simplexml": "*", "ext-json": "*", - "aws/aws-sdk-php": "^3.257", "composer-plugin-api": "^1.0.0 || ^2.0.0", + "aws/aws-sdk-php": "^3.257", "composer/composer": "^2.1.0", "czproject/git-php": "^4.1", "guzzlehttp/guzzle": "^7.4", diff --git a/src/Builder/ClassBuilderFacade.php b/src/Builder/ClassBuilderFacade.php index 665f548b..af7fe35e 100644 --- a/src/Builder/ClassBuilderFacade.php +++ b/src/Builder/ClassBuilderFacade.php @@ -42,8 +42,8 @@ public function resolveClass(string $targetClassName, string $customOrganisation public function storeClass(ClassInformationTransfer $classInformationTransfer): bool { return $this->getFactory() - ->createClassFileWriter() - ->storeClass($classInformationTransfer); + ->createFileWriter() + ->storeFile($classInformationTransfer); } /** diff --git a/src/Builder/ClassGenerator/ClassGenerator.php b/src/Builder/ClassGenerator/ClassGenerator.php index f725fb9e..140fc660 100644 --- a/src/Builder/ClassGenerator/ClassGenerator.php +++ b/src/Builder/ClassGenerator/ClassGenerator.php @@ -93,7 +93,7 @@ public function generateClass(string $className, ?string $parentClass = null): C $syntaxTree = [$classNamespaceBuilder->getNode()]; - $classInformationTransfer->setClassTokenTree($syntaxTree) + $classInformationTransfer->setTokenTree($syntaxTree) ->setFilePath( $moduleDir . '/src' diff --git a/src/Builder/ClassLoader/AbstractLoader.php b/src/Builder/ClassLoader/AbstractLoader.php new file mode 100644 index 00000000..d10cb379 --- /dev/null +++ b/src/Builder/ClassLoader/AbstractLoader.php @@ -0,0 +1,53 @@ +parser = $parser; + $this->lexer = $lexer; + } + + /** + * @param array<\PhpParser\Node\Stmt> $originalSyntaxTree + * + * @return array<\PhpParser\Node> + */ + protected function traverseOriginalSyntaxTree(array $originalSyntaxTree): array + { + $nodeTraverser = new NodeTraverser(); + $nodeTraverser->addVisitor(new NameResolver()); + $nodeTraverser->addVisitor(new CloningVisitor()); + + return $nodeTraverser->traverse($originalSyntaxTree); + } +} diff --git a/src/Builder/ClassLoader/ClassLoader.php b/src/Builder/ClassLoader/ClassLoader.php index 6a45098c..aed4689e 100644 --- a/src/Builder/ClassLoader/ClassLoader.php +++ b/src/Builder/ClassLoader/ClassLoader.php @@ -10,44 +10,19 @@ namespace SprykerSdk\Integrator\Builder\ClassLoader; use Composer\Autoload\ClassLoader as ComposerClassLoader; -use PhpParser\Lexer; use PhpParser\Node; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Namespace_; use PhpParser\NodeFinder; -use PhpParser\NodeTraverser; -use PhpParser\NodeVisitor\CloningVisitor; -use PhpParser\NodeVisitor\NameResolver; -use PhpParser\Parser; use SprykerSdk\Integrator\Transfer\ClassInformationTransfer; -class ClassLoader implements ClassLoaderInterface +class ClassLoader extends AbstractLoader implements ClassLoaderInterface { /** * @var \Composer\Autoload\ClassLoader|null */ private static ?ComposerClassLoader $composerClassLoader = null; - /** - * @var \PhpParser\Parser - */ - protected $parser; - - /** - * @var \PhpParser\Lexer - */ - protected $lexer; - - /** - * @param \PhpParser\Parser $parser - * @param \PhpParser\Lexer $lexer - */ - public function __construct(Parser $parser, Lexer $lexer) - { - $this->parser = $parser; - $this->lexer = $lexer; - } - /** * @param string $className * @@ -74,8 +49,8 @@ public function loadClass(string $className): ClassInformationTransfer $originalSyntaxTree = $this->parser->parse($fileContents); $syntaxTree = $originalSyntaxTree ? $this->traverseOriginalSyntaxTree($originalSyntaxTree) : []; - $classInformationTransfer->setClassTokenTree($syntaxTree) - ->setOriginalClassTokenTree($originalSyntaxTree) + $classInformationTransfer->setTokenTree($syntaxTree) + ->setOriginalTokenTree($originalSyntaxTree) ->setTokens($this->lexer->getTokens()) ->setFilePath(realpath($fileName)); @@ -116,20 +91,6 @@ protected function getParent(array $originalSyntaxTree): ?string return null; } - /** - * @param array<\PhpParser\Node\Stmt> $originalSyntaxTree - * - * @return array<\PhpParser\Node> - */ - protected function traverseOriginalSyntaxTree(array $originalSyntaxTree): array - { - $nodeTraverser = new NodeTraverser(); - $nodeTraverser->addVisitor(new CloningVisitor()); - $nodeTraverser->addVisitor(new NameResolver()); - - return $nodeTraverser->traverse($originalSyntaxTree); - } - /** * @param string $className * diff --git a/src/Builder/ClassLoader/FileLoader.php b/src/Builder/ClassLoader/FileLoader.php new file mode 100644 index 00000000..f4f83735 --- /dev/null +++ b/src/Builder/ClassLoader/FileLoader.php @@ -0,0 +1,43 @@ +setFilePath($path); + if (!file_exists($path)) { + return $fileInformationTransfer; + } + + $fileContents = file_get_contents($path); + if (!$fileContents) { + return $fileInformationTransfer; + } + $fileInformationTransfer->setContent($fileContents); + + $originalSyntaxTree = $this->parser->parse($fileContents); + $syntaxTree = $originalSyntaxTree ? $this->traverseOriginalSyntaxTree($originalSyntaxTree) : []; + + $fileInformationTransfer->setTokenTree($syntaxTree) + ->setOriginalTokenTree($originalSyntaxTree) + ->setTokens($this->lexer->getTokens()); + + return $fileInformationTransfer; + } +} diff --git a/src/Builder/ClassLoader/FileLoaderInterface.php b/src/Builder/ClassLoader/FileLoaderInterface.php new file mode 100644 index 00000000..0c74fc6a --- /dev/null +++ b/src/Builder/ClassLoader/FileLoaderInterface.php @@ -0,0 +1,22 @@ +addVisitor($visitor); } - $classInformationTransfer->setClassTokenTree( - $nodeTraverser->traverse($classInformationTransfer->getClassTokenTree()), + $classInformationTransfer->setTokenTree( + $nodeTraverser->traverse($classInformationTransfer->getTokenTree()), ); return $classInformationTransfer; diff --git a/src/Builder/ClassModifier/CommonClass/CommonClassModifier.php b/src/Builder/ClassModifier/CommonClass/CommonClassModifier.php index 7c41a146..fcdbee21 100644 --- a/src/Builder/ClassModifier/CommonClass/CommonClassModifier.php +++ b/src/Builder/ClassModifier/CommonClass/CommonClassModifier.php @@ -111,7 +111,7 @@ public function overrideMethodFromParent(ClassInformationTransfer $classInformat $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor(new AddMethodVisitor($methodSyntaxTree)); - $classInformationTransfer->setClassTokenTree($nodeTraverser->traverse($classInformationTransfer->getClassTokenTree())); + $classInformationTransfer->setTokenTree($nodeTraverser->traverse($classInformationTransfer->getTokenTree())); return $classInformationTransfer; } @@ -156,7 +156,7 @@ public function replaceMethodBody( $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor(new ReplaceNodePropertiesByNameVisitor($targetMethodName, $methodNodeProperties)); $classInformationTransfer - ->setClassTokenTree($nodeTraverser->traverse($classInformationTransfer->getClassTokenTree())); + ->setTokenTree($nodeTraverser->traverse($classInformationTransfer->getTokenTree())); return $classInformationTransfer; } @@ -172,7 +172,7 @@ public function removeClassMethod(ClassInformationTransfer $classInformationTran $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor(new RemoveMethodVisitor($methodNameToRemove)); $classInformationTransfer - ->setClassTokenTree($nodeTraverser->traverse($classInformationTransfer->getClassTokenTree())); + ->setTokenTree($nodeTraverser->traverse($classInformationTransfer->getTokenTree())); return $classInformationTransfer; } @@ -234,7 +234,7 @@ protected function appendNonLiteralArrayValueToMethodBody( $nodeTraverser->addVisitor(new AddStatementToStatementListVisitor($methodName, $arrayItems, $nodeComparer)); return $classInformationTransfer - ->setClassTokenTree($nodeTraverser->traverse($classInformationTransfer->getClassTokenTree())); + ->setTokenTree($nodeTraverser->traverse($classInformationTransfer->getTokenTree())); } /** diff --git a/src/Builder/ClassModifier/ConfigFile/ConfigFileModifier.php b/src/Builder/ClassModifier/ConfigFile/ConfigFileModifier.php new file mode 100644 index 00000000..ecfcf274 --- /dev/null +++ b/src/Builder/ClassModifier/ConfigFile/ConfigFileModifier.php @@ -0,0 +1,60 @@ +expressionPartialParser = $expressionPartialParser; + } + + /** + * @param \SprykerSdk\Integrator\Transfer\FileInformationTransfer $fileInformationTransfer + * @param string $target + * @param string $value + * + * @return \SprykerSdk\Integrator\Transfer\FileInformationTransfer + */ + public function addArrayItemToEnvConfig( + FileInformationTransfer $fileInformationTransfer, + string $target, + string $value + ): FileInformationTransfer { + $valueStm = $this->expressionPartialParser->parse(sprintf('$var = %s;', $value)); + + /** @var \PhpParser\Node\Expr\ArrayItem|null $arrayItem */ + $arrayItem = (new NodeFinder())->findFirst($valueStm, function (Node $node) { + return $node instanceof ArrayItem; + }); + if (!$arrayItem) { + return $fileInformationTransfer; + } + + $nodeTraverser = new NodeTraverser(); + $nodeTraverser->addVisitor(new AddArrayItemToEnvConfigVisitor($target, $arrayItem)); + + return $fileInformationTransfer + ->setTokenTree($nodeTraverser->traverse($fileInformationTransfer->getTokenTree())); + } +} diff --git a/src/Builder/ClassModifier/ConfigFile/ConfigFileModifierInterface.php b/src/Builder/ClassModifier/ConfigFile/ConfigFileModifierInterface.php new file mode 100644 index 00000000..083fe58e --- /dev/null +++ b/src/Builder/ClassModifier/ConfigFile/ConfigFileModifierInterface.php @@ -0,0 +1,24 @@ +nodeTraverser->addVisitor(new RemoveGlueRelationshipFromClassListVisitor($targetMethodName, $keyClass, $keyConst, $classNameToRemove)); - $classInformationTransfer->setClassTokenTree($this->nodeTraverser->traverse($classInformationTransfer->getClassTokenTree())); + $classInformationTransfer->setTokenTree($this->nodeTraverser->traverse($classInformationTransfer->getTokenTree())); return $classInformationTransfer; } diff --git a/src/Builder/ClassModifier/GlueRelationship/Wire/WireGlueRelationshipModifier.php b/src/Builder/ClassModifier/GlueRelationship/Wire/WireGlueRelationshipModifier.php index 023d617a..ab2ba480 100644 --- a/src/Builder/ClassModifier/GlueRelationship/Wire/WireGlueRelationshipModifier.php +++ b/src/Builder/ClassModifier/GlueRelationship/Wire/WireGlueRelationshipModifier.php @@ -57,7 +57,7 @@ public function wire( $methodBody = $this->getMethodBody($methodNode, $classNameToAdd, $keyClass, $keyConst); $this->nodeTraverser->addVisitor(new MethodBodyExtendVisitor($targetMethodName, $methodBody)); - $classInformationTransfer->setClassTokenTree($this->nodeTraverser->traverse($classInformationTransfer->getClassTokenTree())); + $classInformationTransfer->setTokenTree($this->nodeTraverser->traverse($classInformationTransfer->getTokenTree())); return $classInformationTransfer; } diff --git a/src/Builder/ClassWriter/ClassFileWriterInterface.php b/src/Builder/ClassWriter/ClassFileWriterInterface.php deleted file mode 100644 index 02703361..00000000 --- a/src/Builder/ClassWriter/ClassFileWriterInterface.php +++ /dev/null @@ -1,22 +0,0 @@ -isClassIdentifier($expression); + } + + /** + * @param string $expression + * + * @return bool + */ + protected function isClassIdentifier(string $expression): bool + { + $containsBackslash = strpos($expression, '\\') !== false; + $containsDoubleColon = strpos($expression, '::') !== false; + + return $containsBackslash && $containsDoubleColon; } /** diff --git a/src/Builder/Creator/MethodCreator.php b/src/Builder/Creator/MethodCreator.php index 913f2534..464e9359 100644 --- a/src/Builder/Creator/MethodCreator.php +++ b/src/Builder/Creator/MethodCreator.php @@ -171,7 +171,7 @@ public function createMethod( $nodeTraverser->addVisitor(new AddMethodVisitor($classMethod)); return $classInformationTransfer - ->setClassTokenTree($nodeTraverser->traverse($classInformationTransfer->getClassTokenTree())); + ->setTokenTree($nodeTraverser->traverse($classInformationTransfer->getTokenTree())); } /** diff --git a/src/Builder/Exception/ValueExtractorException.php b/src/Builder/Exception/ValueExtractorException.php new file mode 100644 index 00000000..6b93abfc --- /dev/null +++ b/src/Builder/Exception/ValueExtractorException.php @@ -0,0 +1,16 @@ +valueExtractorStrategyCollection = $valueExtractorStrategyCollection; + } + + /** + * @param array<\PhpParser\Node> $syntaxTree + * + * @throws \RuntimeException + * + * @return array + */ + public function extractExpressions(array $syntaxTree): array + { + $expressions = []; + /** @var \PhpParser\Node\Stmt\Expression $expression */ + foreach ($syntaxTree as $expression) { + if (!$this->isConfigAssignStatement($expression)) { + continue; + } + + /** @var \PhpParser\Node\Expr\Assign $assignExpression */ + $assignExpression = $expression->expr; + $chainAssignValue = $this->extractChainAssignValue($assignExpression, new ChainAssignValueTransfer()); + + if ($chainAssignValue->getValue() === null) { + throw new RuntimeException( + sprintf('Chain value is not found for conf chain %s', implode(', ', $chainAssignValue->getKeys())), + ); + } + + foreach ($chainAssignValue->getKeys() as $key) { + try { + if (!isset($expressions[$key]) || !is_array($expressions[$key])) { + $expressions[$key] = $this->getValue($chainAssignValue->getValue()); + + continue; + } + $expressions[$key] = [...$expressions[$key], ...$this->getValue($chainAssignValue->getValue())]; + } catch (ValueExtractorException $exception) { + continue; + } + } + } + + return $expressions; + } + + /** + * @param \PhpParser\Node\Expr\Assign $expression + * @param \SprykerSdk\Integrator\Transfer\ChainAssignValueTransfer $chainAssignValueDto + * + * @return \SprykerSdk\Integrator\Transfer\ChainAssignValueTransfer + */ + protected function extractChainAssignValue(Assign $expression, ChainAssignValueTransfer $chainAssignValueDto): ChainAssignValueTransfer + { + /** @var \PhpParser\Node\Expr\ArrayDimFetch $arrayDimFetchExpression */ + $arrayDimFetchExpression = $expression->var; + /** @var \PhpParser\Node\Expr\ClassConstFetch $constant */ + $constant = $arrayDimFetchExpression->dim; + + $chainAssignValueDto->addKey(sprintf('\%s::%s', $constant->class->toString(), $constant->name->toString())); + + if ($expression->expr instanceof Assign && $expression->expr->var instanceof ArrayDimFetch) { + return $this->extractChainAssignValue($expression->expr, $chainAssignValueDto); + } + + $chainAssignValueDto->setValue($expression->expr); + + return $chainAssignValueDto; + } + + /** + * @param \PhpParser\Node $statement + * + * @return bool + */ + protected function isConfigAssignStatement(Node $statement): bool + { + return $statement instanceof Expression + && $statement->expr instanceof Assign + && $statement->expr->var instanceof ArrayDimFetch + && $statement->expr->var->dim instanceof ClassConstFetch + && $statement->expr->var->var instanceof Variable + && $statement->expr->var->var->name === 'config'; + } + + /** + * @param \PhpParser\Node\Expr $valueExpression + * + * @return mixed + */ + protected function getValue(Expr $valueExpression) + { + $extractedValueObject = $this->valueExtractorStrategyCollection->execute($valueExpression); + + $value = $extractedValueObject->getValue(); + if ($extractedValueObject->isLiteral()) { + $value = [ + 'value' => $extractedValueObject->getValue(), + 'is_literal' => true, + ]; + } + + return $value; + } +} diff --git a/src/Builder/Extractor/ExpressionExtractorInterface.php b/src/Builder/Extractor/ExpressionExtractorInterface.php new file mode 100644 index 00000000..0fbab330 --- /dev/null +++ b/src/Builder/Extractor/ExpressionExtractorInterface.php @@ -0,0 +1,22 @@ + $syntaxTree + * + * @throws \RuntimeException + * + * @return array + */ + public function extractExpressions(array $syntaxTree): array; +} diff --git a/src/Builder/Extractor/ValueExtractor/AbstractValueExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/AbstractValueExtractorStrategy.php new file mode 100644 index 00000000..4bee28fd --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/AbstractValueExtractorStrategy.php @@ -0,0 +1,113 @@ +value); + } + if ($this->isNonVarExportExpression($expression)) { + $expressionValue = $valueExtractorStrategyCollection->execute($expression)->getValue(); + if (is_bool($expressionValue)) { + $expressionValue = var_export($expressionValue, true); + } + + return sprintf('%s', $expressionValue); + } + + $result = $valueExtractorStrategyCollection->execute($expression)->getValue(); + if (is_array($result)) { + return $this->createArrayStringFromResult($result); + } + + if (is_string($result)) { + return $result; + } + + return var_export($result, true); + } + + /** + * @param \PhpParser\Node\Expr $expression + * + * @return bool + */ + protected function isNonVarExportExpression(Expr $expression): bool + { + return $expression instanceof StaticCall + || $expression instanceof ClassConstFetch + || $expression instanceof FuncCall + || $expression instanceof ConstFetch + || $expression instanceof MethodCall + || $expression instanceof Variable + || $expression instanceof Ternary; + } + + /** + * @param array $array + * + * @return string + */ + protected function createArrayStringFromResult(array $array): string + { + $result = []; + foreach ($array as $key => $value) { + if (is_array($value)) { + $value = $this->createArrayStringFromResult($value); + } + if (is_int($key)) { + $result[] = $value; + + continue; + } + if (!$this->isConstant($key)) { + $key = sprintf('\'%s\'', $key); + } + if (!$this->isConstant($value)) { + $value = sprintf('\'%s\'', $value); + } + + $result[] = sprintf('%s => %s', $key, $value); + } + + return sprintf('[%s]', implode(', ', $result)); + } + + /** + * @param string $value + * + * @return bool + */ + protected function isConstant(string $value): bool + { + return (bool)strpos($value, '::'); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/ArrayDimValueExtractor.php b/src/Builder/Extractor/ValueExtractor/ArrayDimValueExtractor.php new file mode 100644 index 00000000..4cda0a6d --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/ArrayDimValueExtractor.php @@ -0,0 +1,49 @@ +var; + /** @var \PhpParser\Node\Identifier $varName */ + $varName = $variable->name; + /** @var \PhpParser\Node\Expr $dim */ + $dim = $expression->dim; + + $key = $valueExtractorStrategyCollection->execute($dim); + + return new ExtractedValueTransfer(sprintf('$%s[%s]', $varName, $key->getValue()), true); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/ArrayValueExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/ArrayValueExtractorStrategy.php new file mode 100644 index 00000000..d4f70caa --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/ArrayValueExtractorStrategy.php @@ -0,0 +1,62 @@ +items as $key => $item) { + if (!$item->key) { + $array[] = $valueExtractorStrategyCollection->execute($item->value)->getValue(); + + continue; + } + if ($item->key instanceof ClassConstFetch) { + $key = $valueExtractorStrategyCollection->execute($item->key)->getValue(); + } + if ($item->key instanceof String_) { + $key = $item->key->value; + $array[$key] = $valueExtractorStrategyCollection->execute($item->value)->getValue(); + + continue; + } + $array[$key] = $valueExtractorStrategyCollection->execute($item->value)->getValue(); + } + + return new ExtractedValueTransfer($array); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/CastValueExtractor.php b/src/Builder/Extractor/ValueExtractor/CastValueExtractor.php new file mode 100644 index 00000000..4d36338b --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/CastValueExtractor.php @@ -0,0 +1,73 @@ +execute($expression->expr); + + return new ExtractedValueTransfer( + sprintf('(%s)%s', $this->generateTypeCastString($expression), $value->getValue()), + true, + ); + } + + /** + * @param \PhpParser\Node\Expr\Cast $castExpression + * + * @return string + */ + protected function generateTypeCastString(Cast $castExpression): string + { + if ($castExpression instanceof Double) { + return 'float'; + } + + $className = get_class($castExpression); + $classNameParts = explode('\\', $className); + + $classNamePart = end($classNameParts); + + return str_replace('_', '', mb_strtolower($classNamePart)); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/ClassConstFetchValueExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/ClassConstFetchValueExtractorStrategy.php new file mode 100644 index 00000000..2c1722ac --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/ClassConstFetchValueExtractorStrategy.php @@ -0,0 +1,44 @@ +class->toString(), '\\') ? '\\' : ''; + + return new ExtractedValueTransfer( + sprintf('%s%s::%s', $prefix, $expression->class->toString(), $expression->name->toString()), + ); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/ConcatValueExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/ConcatValueExtractorStrategy.php new file mode 100644 index 00000000..dae4c293 --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/ConcatValueExtractorStrategy.php @@ -0,0 +1,44 @@ +getQuotedValueExpression($expression->left, $valueExtractorStrategyCollection); + $rightPart = $this->getQuotedValueExpression($expression->right, $valueExtractorStrategyCollection); + + return new ExtractedValueTransfer( + sprintf('%s . %s', $leftPart, $rightPart), + true, + ); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/ConstFetchValueExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/ConstFetchValueExtractorStrategy.php new file mode 100644 index 00000000..9b0c9be3 --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/ConstFetchValueExtractorStrategy.php @@ -0,0 +1,62 @@ +filterValue($expression->name->toString()); + + return new ExtractedValueTransfer($value, $this->isLiteral($value)); + } + + /** + * @param mixed $value + * + * @return bool + */ + protected function filterValue($value): bool + { + return filter_var($value, FILTER_VALIDATE_BOOLEAN); + } + + /** + * @param mixed $value + * + * @return bool + */ + protected function isLiteral($value): bool + { + return !is_bool($value) && $value !== null; + } +} diff --git a/src/Builder/Extractor/ValueExtractor/DefaultIsLiteralExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/DefaultIsLiteralExtractorStrategy.php new file mode 100644 index 00000000..0144f5b4 --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/DefaultIsLiteralExtractorStrategy.php @@ -0,0 +1,43 @@ +prettyPrintExpr($expression), + true, + ); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/FloatValueExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/FloatValueExtractorStrategy.php new file mode 100644 index 00000000..ca8f1c08 --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/FloatValueExtractorStrategy.php @@ -0,0 +1,40 @@ +value); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/FuncCallValueExtractor.php b/src/Builder/Extractor/ValueExtractor/FuncCallValueExtractor.php new file mode 100644 index 00000000..60aa95c7 --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/FuncCallValueExtractor.php @@ -0,0 +1,73 @@ +name->toString(); + + $args = []; + foreach ($expression->args as $arg) { + $args[] = $this->getQuotedValueExpression($arg->value, $valueExtractorStrategyCollection); + } + + return new ExtractedValueTransfer( + sprintf('%s(%s)', $funcName, $this->recursiveImplodeArguments($args)), + true, + ); + } + + /** + * @param array $arguments + * + * @return string + */ + protected function recursiveImplodeArguments(array $arguments): string + { + $implodeArguments = []; + foreach ($arguments as $argumentKey => $argumentValue) { + if (is_array($argumentValue)) { + $argumentValue = sprintf('[%s]', $this->recursiveImplodeArguments($argumentValue)); + } + if (is_int($argumentKey)) { + $implodeArguments[] = $argumentValue; + + continue; + } + $implodeArguments[] = sprintf('%s => %s', $argumentKey, $argumentValue); + } + + return implode(', ', $implodeArguments); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/IntegerValueExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/IntegerValueExtractorStrategy.php new file mode 100644 index 00000000..d6e93d15 --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/IntegerValueExtractorStrategy.php @@ -0,0 +1,40 @@ +value); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/MethodCallExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/MethodCallExtractorStrategy.php new file mode 100644 index 00000000..a6e099b4 --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/MethodCallExtractorStrategy.php @@ -0,0 +1,26 @@ +value); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/TernaryValueExtractorStrategy.php b/src/Builder/Extractor/ValueExtractor/TernaryValueExtractorStrategy.php new file mode 100644 index 00000000..b674c0f6 --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/TernaryValueExtractorStrategy.php @@ -0,0 +1,53 @@ +getQuotedValueExpression($expression->cond, $valueExtractorStrategyCollection); + $elseStatementExpression = $this->getQuotedValueExpression($expression->else, $valueExtractorStrategyCollection); + + if ($expression->if) { + $ifStatementExpression = $this->getQuotedValueExpression($expression->if, $valueExtractorStrategyCollection); + + return new ExtractedValueTransfer( + sprintf('%s ? %s : %s', $conditionExpression, $ifStatementExpression, $elseStatementExpression), + true, + ); + } + + return new ExtractedValueTransfer( + sprintf('%s ?: %s', $conditionExpression, $elseStatementExpression), + true, + ); + } +} diff --git a/src/Builder/Extractor/ValueExtractor/ValueExtractorStrategyCollection.php b/src/Builder/Extractor/ValueExtractor/ValueExtractorStrategyCollection.php new file mode 100644 index 00000000..9b3fa3c3 --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/ValueExtractorStrategyCollection.php @@ -0,0 +1,79 @@ + + */ + protected const STRATEGIES = [ + ClassConstFetchValueExtractorStrategy::class, + ConstFetchValueExtractorStrategy::class, + FloatValueExtractorStrategy::class, + IntegerValueExtractorStrategy::class, + StringValueExtractorStrategy::class, + ConcatValueExtractorStrategy::class, + ArrayValueExtractorStrategy::class, + CastValueExtractor::class, + ArrayDimValueExtractor::class, + FuncCallValueExtractor::class, + TernaryValueExtractorStrategy::class, + MethodCallExtractorStrategy::class, + VariableExtractorStrategy::class, + DefaultIsLiteralExtractorStrategy::class, + ]; + + /** + * @var array<\SprykerSdk\Integrator\Builder\Extractor\ValueExtractor\ValueExtractorStrategyInterface> + */ + protected $strategiesCache = []; + + /** + * @param \PhpParser\Node\Expr $expression + * + * @throws \SprykerSdk\Integrator\Builder\Exception\ValueExtractorException + * + * @return \SprykerSdk\Integrator\Transfer\ExtractedValueTransfer + */ + public function execute(Expr $expression): ExtractedValueTransfer + { + $strategies = $this->getStrategies(); + foreach ($strategies as $strategy) { + if ($strategy->isApplicable($expression)) { + return $strategy->extractValue($expression, $this); + } + } + + throw new ValueExtractorException(sprintf('%s expression type is not supported', get_class($expression))); + } + + /** + * @return array<\SprykerSdk\Integrator\Builder\Extractor\ValueExtractor\ValueExtractorStrategyInterface> + */ + protected function getStrategies(): array + { + if ($this->strategiesCache) { + return $this->strategiesCache; + } + + foreach (static::STRATEGIES as $strategyClass) { + /** @var \SprykerSdk\Integrator\Builder\Extractor\ValueExtractor\ValueExtractorStrategyInterface $strategy */ + $strategy = new $strategyClass(); + $this->strategiesCache[] = $strategy; + } + + return $this->strategiesCache; + } +} diff --git a/src/Builder/Extractor/ValueExtractor/ValueExtractorStrategyInterface.php b/src/Builder/Extractor/ValueExtractor/ValueExtractorStrategyInterface.php new file mode 100644 index 00000000..dad0f6be --- /dev/null +++ b/src/Builder/Extractor/ValueExtractor/ValueExtractorStrategyInterface.php @@ -0,0 +1,34 @@ +name) ? $expression->name : 'var'), true); + } +} diff --git a/src/Builder/FileBuilderFacade.php b/src/Builder/FileBuilderFacade.php new file mode 100644 index 00000000..f7bcfa1b --- /dev/null +++ b/src/Builder/FileBuilderFacade.php @@ -0,0 +1,42 @@ +getFactory() + ->createFileLoader() + ->loadFile($path); + } + + /** + * @param \SprykerSdk\Integrator\Transfer\FileInformationTransfer $fileInformationTransfer + * + * @return bool + */ + public function storeFile(FileInformationTransfer $fileInformationTransfer): bool + { + return $this->getFactory() + ->createFileWriter() + ->storeFile($fileInformationTransfer); + } +} diff --git a/src/Builder/FileBuilderFacadeInterface.php b/src/Builder/FileBuilderFacadeInterface.php new file mode 100644 index 00000000..90689034 --- /dev/null +++ b/src/Builder/FileBuilderFacadeInterface.php @@ -0,0 +1,29 @@ +getOriginalClassTokenTree()) { + if ($classInformationTransfer->getOriginalTokenTree()) { $code = $this->classPrinter->printFormatPreserving( - $classInformationTransfer->getClassTokenTree(), - $classInformationTransfer->getOriginalClassTokenTree(), + $classInformationTransfer->getTokenTree(), + $classInformationTransfer->getOriginalTokenTree(), $classInformationTransfer->getTokens(), ); } else { $code = $this->classPrinter->prettyPrintFile( - $classInformationTransfer->getClassTokenTree(), + $classInformationTransfer->getTokenTree(), ); } diff --git a/src/Builder/FileWriter/FileWriterInterface.php b/src/Builder/FileWriter/FileWriterInterface.php new file mode 100644 index 00000000..e2ebcf42 --- /dev/null +++ b/src/Builder/FileWriter/FileWriterInterface.php @@ -0,0 +1,22 @@ +findFirst($classInformationTransfer->getClassTokenTree(), function (Node $node) use ($targetMethodName) { + $node = (new NodeFinder())->findFirst($classInformationTransfer->getTokenTree(), function (Node $node) use ($targetMethodName) { return $node instanceof ClassMethod && $node->name->toString() === $targetMethodName; }); @@ -44,7 +44,7 @@ public function findMethodNode(ClassInformationTransfer $classInformationTransfe public function findConstantNode(ClassInformationTransfer $classInformationTransfer, string $targetNodeName): ?ClassConst { /** @var \PhpParser\Node\Stmt\ClassConst|null $node */ - $node = (new NodeFinder())->findFirst($classInformationTransfer->getClassTokenTree(), function (Node $node) use ($targetNodeName) { + $node = (new NodeFinder())->findFirst($classInformationTransfer->getTokenTree(), function (Node $node) use ($targetNodeName) { if (!($node instanceof ClassConst)) { return false; } @@ -69,7 +69,7 @@ public function findConstantNode(ClassInformationTransfer $classInformationTrans public function findClassNode(ClassInformationTransfer $classInformationTransfer): ?Class_ { /** @var \PhpParser\Node\Stmt\Class_|null $node */ - $node = (new NodeFinder())->findFirst($classInformationTransfer->getClassTokenTree(), function (Node $node) { + $node = (new NodeFinder())->findFirst($classInformationTransfer->getTokenTree(), function (Node $node) { return $node instanceof Class_; }); @@ -85,7 +85,7 @@ public function findClassNode(ClassInformationTransfer $classInformationTransfer public function hasClassMethodName(ClassInformationTransfer $classInformationTransfer, string $methodName): bool { /** @var \PhpParser\Node\Stmt\ClassMethod $node */ - $node = (new NodeFinder())->findFirst($classInformationTransfer->getClassTokenTree(), function (Node $node) use ($methodName) { + $node = (new NodeFinder())->findFirst($classInformationTransfer->getTokenTree(), function (Node $node) use ($methodName) { return $node instanceof ClassMethod && $node->name->toString() === $methodName; }); if ($node) { diff --git a/src/Builder/Printer/ClassDiffPrinter.php b/src/Builder/Printer/ClassDiffPrinter.php index 8cc49e0d..226c9380 100644 --- a/src/Builder/Printer/ClassDiffPrinter.php +++ b/src/Builder/Printer/ClassDiffPrinter.php @@ -36,20 +36,20 @@ public function __construct(ClassPrinter $classPrinter) public function printDiff(ClassInformationTransfer $classInformationTransfer): string { $originalCode = ''; - if ($classInformationTransfer->getOriginalClassTokenTree()) { + if ($classInformationTransfer->getOriginalTokenTree()) { $code = $this->classPrinter->printFormatPreserving( - $classInformationTransfer->getClassTokenTree(), - $classInformationTransfer->getOriginalClassTokenTree(), + $classInformationTransfer->getTokenTree(), + $classInformationTransfer->getOriginalTokenTree(), $classInformationTransfer->getTokens(), ); $originalCode = $this->classPrinter->printFormatPreserving( - $classInformationTransfer->getOriginalClassTokenTree(), - $classInformationTransfer->getOriginalClassTokenTree(), + $classInformationTransfer->getOriginalTokenTree(), + $classInformationTransfer->getOriginalTokenTree(), $classInformationTransfer->getTokens(), ); } else { $code = $this->classPrinter->prettyPrintFile( - $classInformationTransfer->getClassTokenTree(), + $classInformationTransfer->getTokenTree(), ); } diff --git a/src/Builder/Visitor/AddArrayItemToEnvConfigVisitor.php b/src/Builder/Visitor/AddArrayItemToEnvConfigVisitor.php new file mode 100644 index 00000000..9d739cc8 --- /dev/null +++ b/src/Builder/Visitor/AddArrayItemToEnvConfigVisitor.php @@ -0,0 +1,114 @@ +target = $target; + $this->value = $value; + } + + /** + * @param \PhpParser\Node $node + * + * @return \PhpParser\Node|int|null + */ + public function enterNode(Node $node) + { + if ($this->isValueApplied) { + return $node; + } + + if ($node instanceof Expression) { + $this->isConfigAssingFound = false; + if ($this->isConfigAssignStatement($node)) { + $this->isConfigAssingFound = true; + } + } + + if ($this->isConfigAssingFound && $node instanceof Assign) { + /** @var \PhpParser\Node\Expr\ArrayDimFetch $arrayDimFetchExpression */ + $arrayDimFetchExpression = $node->var; + /** @var \PhpParser\Node\Expr\ClassConstFetch $constant */ + $constant = $arrayDimFetchExpression->dim; + + $key = sprintf('\%s::%s', $constant->class->toString(), $constant->name->toString()); + + if ($key === $this->target) { + $this->isTargetFound = true; + } + } + + if ($this->isTargetFound) { + if ($node instanceof Array_) { + $node->items[] = $this->value; + $this->isValueApplied = true; + } + } + + return $node; + } + + /** + * @param \PhpParser\Node $statement + * + * @return bool + */ + protected function isConfigAssignStatement(Node $statement): bool + { + return $statement instanceof Expression + && $statement->expr instanceof Assign + && $statement->expr->var instanceof ArrayDimFetch + && $statement->expr->var->dim instanceof ClassConstFetch + && $statement->expr->var->var instanceof Variable + && $statement->expr->var->var->name === 'config'; + } +} diff --git a/src/Builder/Visitor/AddPluginToPluginCollectionVisitor.php b/src/Builder/Visitor/AddPluginToPluginCollectionVisitor.php index 9947cb7c..61f7149e 100644 --- a/src/Builder/Visitor/AddPluginToPluginCollectionVisitor.php +++ b/src/Builder/Visitor/AddPluginToPluginCollectionVisitor.php @@ -171,14 +171,14 @@ protected function getMethodName(Node $node): ?string /** * @var array<\PhpParser\Node\Stmt\ClassMethod> $possibleNodeMethods */ - $possibleNodeMethods = (new NodeFinder())->find($returnClass->getClassTokenTree(), function (Node $node) { + $possibleNodeMethods = (new NodeFinder())->find($returnClass->getTokenTree(), function (Node $node) { return $node instanceof ClassMethod && $node->flags === Class_::MODIFIER_PUBLIC; }); /** * @var array<\PhpParser\Node\Stmt\Class_> $sourceNodeInterfaces */ - $sourceNodeInterfaces = (new NodeFinder())->find($sourceClass->getClassTokenTree(), function (Node $node) { + $sourceNodeInterfaces = (new NodeFinder())->find($sourceClass->getTokenTree(), function (Node $node) { return $node instanceof Class_ && $node->implements; }); if (!$sourceNodeInterfaces) { diff --git a/src/IntegratorFactory.php b/src/IntegratorFactory.php index 3156d102..7bc12dbb 100644 --- a/src/IntegratorFactory.php +++ b/src/IntegratorFactory.php @@ -31,6 +31,8 @@ use SprykerSdk\Integrator\Builder\ClassGenerator\ClassGeneratorInterface; use SprykerSdk\Integrator\Builder\ClassLoader\ClassLoader; use SprykerSdk\Integrator\Builder\ClassLoader\ClassLoaderInterface; +use SprykerSdk\Integrator\Builder\ClassLoader\FileLoader; +use SprykerSdk\Integrator\Builder\ClassLoader\FileLoaderInterface; use SprykerSdk\Integrator\Builder\ClassMetadataBuilder\ClassMetadataBuilder; use SprykerSdk\Integrator\Builder\ClassMetadataBuilder\ClassMetadataBuilderInterface; use SprykerSdk\Integrator\Builder\ClassModifier\ClassConstant\ClassConstantModifier; @@ -63,14 +65,14 @@ use SprykerSdk\Integrator\Builder\ClassModifier\ClassInstanceModifierStrategy\Wire\WireClassInstanceModifierStrategyInterface; use SprykerSdk\Integrator\Builder\ClassModifier\CommonClass\CommonClassModifier; use SprykerSdk\Integrator\Builder\ClassModifier\CommonClass\CommonClassModifierInterface; +use SprykerSdk\Integrator\Builder\ClassModifier\ConfigFile\ConfigFileModifier; +use SprykerSdk\Integrator\Builder\ClassModifier\ConfigFile\ConfigFileModifierInterface; use SprykerSdk\Integrator\Builder\ClassModifier\GlueRelationship\Unwire\UnwireGlueRelationshipModifier; use SprykerSdk\Integrator\Builder\ClassModifier\GlueRelationship\Unwire\UnwireGlueRelationshipModifierInterface; use SprykerSdk\Integrator\Builder\ClassModifier\GlueRelationship\Wire\WireGlueRelationshipModifier; use SprykerSdk\Integrator\Builder\ClassModifier\GlueRelationship\Wire\WireGlueRelationshipModifierInterface; use SprykerSdk\Integrator\Builder\ClassResolver\ClassResolver; use SprykerSdk\Integrator\Builder\ClassResolver\ClassResolverInterface; -use SprykerSdk\Integrator\Builder\ClassWriter\ClassFileWriter; -use SprykerSdk\Integrator\Builder\ClassWriter\ClassFileWriterInterface; use SprykerSdk\Integrator\Builder\ConfigurationEnvironmentBuilder\ArrayConfigurationEnvironmentStrategy; use SprykerSdk\Integrator\Builder\ConfigurationEnvironmentBuilder\BooleanConfigurationEnvironmentStrategy; use SprykerSdk\Integrator\Builder\ConfigurationEnvironmentBuilder\ClassConfigurationEnvironmentStrategy; @@ -87,6 +89,10 @@ use SprykerSdk\Integrator\Builder\Creator\MethodReturnTypeCreatorInterface; use SprykerSdk\Integrator\Builder\Creator\MethodStatementsCreator; use SprykerSdk\Integrator\Builder\Creator\MethodStatementsCreatorInterface; +use SprykerSdk\Integrator\Builder\Extractor\ExpressionExtractor; +use SprykerSdk\Integrator\Builder\Extractor\ExpressionExtractorInterface; +use SprykerSdk\Integrator\Builder\Extractor\ValueExtractor\ValueExtractorStrategyCollection; +use SprykerSdk\Integrator\Builder\FileBuilderFacade; use SprykerSdk\Integrator\Builder\FileNormalizer\CodeSnifferCompositeNormalizer; use SprykerSdk\Integrator\Builder\FileNormalizer\CodeSniffStyleFileNormalizer; use SprykerSdk\Integrator\Builder\FileNormalizer\FileNormalizerInterface; @@ -95,6 +101,8 @@ use SprykerSdk\Integrator\Builder\FileNormalizer\PhpCSFixerFileNormalizer; use SprykerSdk\Integrator\Builder\FileStorage\FileStorageFactory; use SprykerSdk\Integrator\Builder\FileStorage\FileStorageInterface; +use SprykerSdk\Integrator\Builder\FileWriter\FileWriter; +use SprykerSdk\Integrator\Builder\FileWriter\FileWriterInterface; use SprykerSdk\Integrator\Builder\Finder\ClassConstantFinder; use SprykerSdk\Integrator\Builder\Finder\ClassConstantFinderInterface; use SprykerSdk\Integrator\Builder\Finder\ClassNodeFinder; @@ -360,6 +368,9 @@ public function createConfigureEnvManifestStrategy(): ManifestStrategyInterface return new ConfigureEnvManifestStrategy( $this->getConfig(), $this->createClassHelper(), + $this->createExpressionsValueExtractor(), + $this->createConfigFileModifier(), + $this->createFileBuilderFacade(), $this->getConfigurationEnvironmentStrategies(), ); } @@ -533,11 +544,11 @@ public function createClassMetadataBuilder(): ClassMetadataBuilderInterface } /** - * @return \SprykerSdk\Integrator\Builder\ClassWriter\ClassFileWriterInterface + * @return \SprykerSdk\Integrator\Builder\FileWriter\FileWriterInterface */ - public function createClassFileWriter(): ClassFileWriterInterface + public function createFileWriter(): FileWriterInterface { - return new ClassFileWriter($this->createClassPrinter(), $this->createFileStorage()); + return new FileWriter($this->createClassPrinter(), $this->createFileStorage()); } /** @@ -646,6 +657,19 @@ public function createClassLoader(): ClassLoaderInterface ); } + /** + * @return \SprykerSdk\Integrator\Builder\ClassLoader\FileLoaderInterface + */ + public function createFileLoader(): FileLoaderInterface + { + $lexer = $this->createPhpParserLexer(); + + return new FileLoader( + $this->createPhpParserParser($lexer), + $lexer, + ); + } + /** * @return \SprykerSdk\Integrator\Builder\ClassGenerator\ClassGeneratorInterface */ @@ -1183,4 +1207,40 @@ protected function createClassConstantFinder(): ClassConstantFinderInterface { return new ClassConstantFinder($this->createClassNodeFinder()); } + + /** + * @return \SprykerSdk\Integrator\Builder\Extractor\ExpressionExtractorInterface + */ + public function createExpressionsValueExtractor(): ExpressionExtractorInterface + { + return new ExpressionExtractor( + $this->createValueExtractorStrategyCollection(), + ); + } + + /** + * @return \SprykerSdk\Integrator\Builder\Extractor\ValueExtractor\ValueExtractorStrategyCollection + */ + public function createValueExtractorStrategyCollection(): ValueExtractorStrategyCollection + { + return new ValueExtractorStrategyCollection(); + } + + /** + * @return \SprykerSdk\Integrator\Builder\ClassModifier\ConfigFile\ConfigFileModifierInterface + */ + public function createConfigFileModifier(): ConfigFileModifierInterface + { + return new ConfigFileModifier( + $this->createNodeExpressionPartialParser(), + ); + } + + /** + * @return \SprykerSdk\Integrator\Builder\FileBuilderFacade + */ + protected function createFileBuilderFacade(): FileBuilderFacade + { + return new FileBuilderFacade(); + } } diff --git a/src/ManifestStrategy/ConfigureEnvManifestStrategy.php b/src/ManifestStrategy/ConfigureEnvManifestStrategy.php index 7779b367..ce0a5946 100644 --- a/src/ManifestStrategy/ConfigureEnvManifestStrategy.php +++ b/src/ManifestStrategy/ConfigureEnvManifestStrategy.php @@ -9,10 +9,14 @@ namespace SprykerSdk\Integrator\ManifestStrategy; +use SprykerSdk\Integrator\Builder\ClassModifier\ConfigFile\ConfigFileModifierInterface; +use SprykerSdk\Integrator\Builder\Extractor\ExpressionExtractorInterface; +use SprykerSdk\Integrator\Builder\FileBuilderFacade; use SprykerSdk\Integrator\Dependency\Console\InputOutputInterface; use SprykerSdk\Integrator\Exception\ManifestApplyingException; use SprykerSdk\Integrator\Helper\ClassHelperInterface; use SprykerSdk\Integrator\IntegratorConfig; +use SprykerSdk\Integrator\Transfer\FileInformationTransfer; class ConfigureEnvManifestStrategy extends AbstractManifestStrategy { @@ -21,18 +25,42 @@ class ConfigureEnvManifestStrategy extends AbstractManifestStrategy */ protected $configurationEnvironmentStrategies; + /** + * @var \SprykerSdk\Integrator\Builder\Extractor\ExpressionExtractorInterface + */ + protected ExpressionExtractorInterface $expressionsValueExtractor; + + /** + * @var \SprykerSdk\Integrator\Builder\ClassModifier\ConfigFile\ConfigFileModifierInterface + */ + protected ConfigFileModifierInterface $configFileModifier; + + /** + * @var \SprykerSdk\Integrator\Builder\FileBuilderFacade + */ + protected FileBuilderFacade $fileBuilderFacade; + /** * @param \SprykerSdk\Integrator\IntegratorConfig $config * @param \SprykerSdk\Integrator\Helper\ClassHelperInterface $classHelper + * @param \SprykerSdk\Integrator\Builder\Extractor\ExpressionExtractorInterface $expressionsValueExtractor + * @param \SprykerSdk\Integrator\Builder\ClassModifier\ConfigFile\ConfigFileModifierInterface $configFileModifier + * @param \SprykerSdk\Integrator\Builder\FileBuilderFacade $fileBuilderFacade * @param array $configurationEnvironmentBuilders */ public function __construct( IntegratorConfig $config, ClassHelperInterface $classHelper, + ExpressionExtractorInterface $expressionsValueExtractor, + ConfigFileModifierInterface $configFileModifier, + FileBuilderFacade $fileBuilderFacade, array $configurationEnvironmentBuilders ) { parent::__construct($config, $classHelper); + $this->fileBuilderFacade = $fileBuilderFacade; + $this->configFileModifier = $configFileModifier; + $this->expressionsValueExtractor = $expressionsValueExtractor; $this->configurationEnvironmentStrategies = $configurationEnvironmentBuilders; } @@ -77,8 +105,8 @@ public function apply(array $manifest, string $moduleName, InputOutputInterface $configFileName, )); } - if (!$isDry && !$this->targetExists($target)) { - file_put_contents($configFileName, $this->getConfigAppendData($target, $value), FILE_APPEND); + if (!$isDry) { + $this->applyValue($configFileName, $target, $value); } $inputOutput->writeln(sprintf( @@ -92,41 +120,104 @@ public function apply(array $manifest, string $moduleName, InputOutputInterface } /** + * @param string $configFileName * @param string $target + * @param mixed $value * - * @return bool + * @return void */ - protected function targetExists(string $target): bool + protected function applyValue(string $configFileName, string $target, $value): void { - $configFileContent = (string)file_get_contents($this->config->getConfigPath()); + $fileInformationTransfer = $this->fileBuilderFacade->loadFile($configFileName); + $originalExpressions = $this->expressionsValueExtractor->extractExpressions($fileInformationTransfer->getOriginalTokenTree()); - return mb_strpos($configFileContent, $this->getConfigTarget($target)) !== false; + if (!array_key_exists($target, $originalExpressions)) { + file_put_contents($configFileName, $this->getConfigAppendData($target, $value), FILE_APPEND); + + return; + } + + if (!is_array($value) || !empty($value[IntegratorConfig::MANIFEST_KEY_IS_LITERAL])) { + return; + } + + $this->applyDiff( + $fileInformationTransfer, + $target, + $this->compareArrayExpression($value, $originalExpressions, $target), + ); + + $this->fileBuilderFacade->storeFile($fileInformationTransfer); } /** + * @param \SprykerSdk\Integrator\Transfer\FileInformationTransfer $fileInformationTransfer * @param string $target - * @param mixed $value + * @param array $diffValueItems * - * @return string + * @return void */ - protected function getConfigAppendData(string $target, $value): string + protected function applyDiff(FileInformationTransfer $fileInformationTransfer, string $target, array $diffValueItems): void { - $data = PHP_EOL . '$' . $this->config->getConfigVariableName() . '[' . $target . '] = '; + foreach ($diffValueItems as $item) { + if (!is_array($item)) { + $item = [$item]; + } - $data .= $this->prepareValue($value); - $data .= ';' . PHP_EOL; + $this->configFileModifier->addArrayItemToEnvConfig( + $fileInformationTransfer, + $target, + $this->prepareValue($item), + ); + } + } - return $data; + /** + * @param array $manifestValue + * @param array $originalExpressions + * @param string $target + * + * @return array + */ + protected function compareArrayExpression(array $manifestValue, array $originalExpressions, string $target): array + { + $diff = []; + foreach ($manifestValue as $key => $value) { + if (is_int($key)) { + if ( + isset($originalExpressions[$target]) && + is_array($originalExpressions[$target]) && + !in_array($value, $originalExpressions[$target], true) + ) { + $diff[] = $value; + } + + continue; + } + + if (isset($originalExpressions[$target]) && isset($originalExpressions[$target][$key])) { + continue; + } + $diff[] = [$key => $value]; + } + + return $diff; } /** * @param string $target + * @param mixed $value * * @return string */ - protected function getConfigTarget(string $target): string + protected function getConfigAppendData(string $target, $value): string { - return '$' . $this->config->getConfigVariableName() . '[' . $target . ']'; + $data = PHP_EOL . '$' . $this->config->getConfigVariableName() . '[' . $target . '] = '; + + $data .= $this->prepareValue($value); + $data .= ';' . PHP_EOL; + + return $data; } /** diff --git a/src/Transfer/ChainAssignValueTransfer.php b/src/Transfer/ChainAssignValueTransfer.php new file mode 100644 index 00000000..e353bfd3 --- /dev/null +++ b/src/Transfer/ChainAssignValueTransfer.php @@ -0,0 +1,61 @@ + + */ + protected array $keys = []; + + /** + * @var \PhpParser\Node\Expr|null; + */ + protected ?Expr $value = null; + + /** + * @return array + */ + public function getKeys(): array + { + return $this->keys; + } + + /** + * @param string $key + * + * @return void + */ + public function addKey(string $key): void + { + $this->keys[] = $key; + } + + /** + * @return \PhpParser\Node\Expr|null + */ + public function getValue(): ?Expr + { + return $this->value; + } + + /** + * @param \PhpParser\Node\Expr $value + * + * @return void + */ + public function setValue(Expr $value): void + { + $this->value = $value; + } +} diff --git a/src/Transfer/ClassInformationTransfer.php b/src/Transfer/ClassInformationTransfer.php index 0db12ade..eddd100e 100644 --- a/src/Transfer/ClassInformationTransfer.php +++ b/src/Transfer/ClassInformationTransfer.php @@ -10,219 +10,22 @@ namespace SprykerSdk\Integrator\Transfer; use ArrayObject; -use InvalidArgumentException; -use SprykerSdk\Integrator\Transfer\ClassInformationTransfer as TransferClassInformationTransfer; -class ClassInformationTransfer extends AbstractTransfer +class ClassInformationTransfer extends FileInformationTransfer { - /** - * @var string - */ - public const FULLY_QUALIFIED_CLASS_NAME = 'fullyQualifiedClassName'; - - /** - * @var string - */ - public const CLASS_NAME = 'className'; - - /** - * @var string - */ - public const FILE_PATH = 'filePath'; - - /** - * @var string - */ - public const PARENT = 'parent'; - - /** - * @var string - */ - public const CLASS_TOKEN_TREE = 'classTokenTree'; - - /** - * @var string - */ - public const ORIGINAL_CLASS_TOKEN_TREE = 'originalClassTokenTree'; - - /** - * @var string - */ - public const TOKENS = 'tokens'; - - /** - * @var string - */ - public const METHODS = 'methods'; - - /** - * @var string|null - */ - protected $fullyQualifiedClassName; - /** * @var string|null */ - protected $className; + protected ?string $fullyQualifiedClassName = null; /** * @var string|null */ - protected $filePath; - - /** - * @var static|null - */ - protected $parent; - - /** - * @var array - */ - protected $classTokenTree = []; - - /** - * @var array - */ - protected $originalClassTokenTree = []; + protected ?string $className = null; - /** - * @var array - */ - protected $tokens = []; - - /** - * @var \ArrayObject - */ - protected $methods; - - /** - * @var array - */ - protected $transferPropertyNameMap = [ - 'fully_qualified_class_name' => 'fullyQualifiedClassName', - 'fullyQualifiedClassName' => 'fullyQualifiedClassName', - 'FullyQualifiedClassName' => 'fullyQualifiedClassName', - 'class_name' => 'className', - 'className' => 'className', - 'ClassName' => 'className', - 'file_path' => 'filePath', - 'filePath' => 'filePath', - 'FilePath' => 'filePath', - 'parent' => 'parent', - 'Parent' => 'parent', - 'class_token_tree' => 'classTokenTree', - 'classTokenTree' => 'classTokenTree', - 'ClassTokenTree' => 'classTokenTree', - 'original_class_token_tree' => 'originalClassTokenTree', - 'originalClassTokenTree' => 'originalClassTokenTree', - 'OriginalClassTokenTree' => 'originalClassTokenTree', - 'tokens' => 'tokens', - 'Tokens' => 'tokens', - 'methods' => 'methods', - 'Methods' => 'methods', - ]; + protected ?ClassInformationTransfer $parent = null; - /** - * @var array - */ - protected $transferMetadata = [ - self::FULLY_QUALIFIED_CLASS_NAME => [ - 'type' => 'string', - 'type_shim' => null, - 'name_underscore' => 'fully_qualified_class_name', - 'is_collection' => false, - 'is_transfer' => false, - 'is_value_object' => false, - 'rest_request_parameter' => 'no', - 'is_associative' => false, - 'is_nullable' => false, - 'is_strict' => false, - ], - self::CLASS_NAME => [ - 'type' => 'string', - 'type_shim' => null, - 'name_underscore' => 'class_name', - 'is_collection' => false, - 'is_transfer' => false, - 'is_value_object' => false, - 'rest_request_parameter' => 'no', - 'is_associative' => false, - 'is_nullable' => false, - 'is_strict' => false, - ], - self::FILE_PATH => [ - 'type' => 'string', - 'type_shim' => null, - 'name_underscore' => 'file_path', - 'is_collection' => false, - 'is_transfer' => false, - 'is_value_object' => false, - 'rest_request_parameter' => 'no', - 'is_associative' => false, - 'is_nullable' => false, - 'is_strict' => false, - ], - self::PARENT => [ - 'type' => 'Shared\Transfer\ClassInformationTransfer', - 'type_shim' => null, - 'name_underscore' => 'parent', - 'is_collection' => false, - 'is_transfer' => true, - 'is_value_object' => false, - 'rest_request_parameter' => 'no', - 'is_associative' => false, - 'is_nullable' => false, - 'is_strict' => false, - ], - self::CLASS_TOKEN_TREE => [ - 'type' => 'array', - 'type_shim' => null, - 'name_underscore' => 'class_token_tree', - 'is_collection' => false, - 'is_transfer' => false, - 'is_value_object' => false, - 'rest_request_parameter' => 'no', - 'is_associative' => false, - 'is_nullable' => false, - 'is_strict' => false, - ], - self::ORIGINAL_CLASS_TOKEN_TREE => [ - 'type' => 'array', - 'type_shim' => null, - 'name_underscore' => 'original_class_token_tree', - 'is_collection' => false, - 'is_transfer' => false, - 'is_value_object' => false, - 'rest_request_parameter' => 'no', - 'is_associative' => false, - 'is_nullable' => false, - 'is_strict' => false, - ], - self::TOKENS => [ - 'type' => 'array', - 'type_shim' => null, - 'name_underscore' => 'tokens', - 'is_collection' => false, - 'is_transfer' => false, - 'is_value_object' => false, - 'rest_request_parameter' => 'no', - 'is_associative' => false, - 'is_nullable' => false, - 'is_strict' => false, - ], - self::METHODS => [ - 'type' => 'Shared\Transfer\MethodInformationTransfer', - 'type_shim' => null, - 'name_underscore' => 'methods', - 'is_collection' => true, - 'is_transfer' => true, - 'is_value_object' => false, - 'rest_request_parameter' => 'no', - 'is_associative' => false, - 'is_nullable' => false, - 'is_strict' => false, - ], - ]; + protected ArrayObject $methods; /** * @param string|null $fullyQualifiedClassName @@ -232,7 +35,6 @@ class ClassInformationTransfer extends AbstractTransfer public function setFullyQualifiedClassName(?string $fullyQualifiedClassName) { $this->fullyQualifiedClassName = $fullyQualifiedClassName; - $this->modifiedProperties[static::FULLY_QUALIFIED_CLASS_NAME] = true; return $this; } @@ -251,22 +53,12 @@ public function getFullyQualifiedClassName(): ?string public function getFullyQualifiedClassNameOrFail(): string { if ($this->fullyQualifiedClassName === null) { - $this->throwNullValueException(static::FULLY_QUALIFIED_CLASS_NAME); + $this->throwNullValueException('fullyQualifiedClassName'); } return $this->fullyQualifiedClassName; } - /** - * @return $this - */ - public function requireFullyQualifiedClassName() - { - $this->assertPropertyIsSet(static::FULLY_QUALIFIED_CLASS_NAME); - - return $this; - } - /** * @param string|null $className * @@ -275,7 +67,6 @@ public function requireFullyQualifiedClassName() public function setClassName(?string $className) { $this->className = $className; - $this->modifiedProperties[static::CLASS_NAME] = true; return $this; } @@ -288,71 +79,6 @@ public function getClassName(): ?string return $this->className; } - /** - * @return string - */ - public function getClassNameOrFail(): string - { - if ($this->className === null) { - $this->throwNullValueException(static::CLASS_NAME); - } - - return $this->className; - } - - /** - * @return $this - */ - public function requireClassName() - { - $this->assertPropertyIsSet(static::CLASS_NAME); - - return $this; - } - - /** - * @param string|null $filePath - * - * @return $this - */ - public function setFilePath(?string $filePath) - { - $this->filePath = $filePath; - $this->modifiedProperties[static::FILE_PATH] = true; - - return $this; - } - - /** - * @return string|null - */ - public function getFilePath(): ?string - { - return $this->filePath; - } - - /** - * @return string - */ - public function getFilePathOrFail(): string - { - if ($this->filePath === null) { - $this->throwNullValueException(static::FILE_PATH); - } - - return $this->filePath; - } - - /** - * @return $this - */ - public function requireFilePath() - { - $this->assertPropertyIsSet(static::FILE_PATH); - - return $this; - } - /** * @param static|null $parent * @@ -361,7 +87,6 @@ public function requireFilePath() public function setParent(?ClassInformationTransfer $parent = null) { $this->parent = $parent; - $this->modifiedProperties[static::PARENT] = true; return $this; } @@ -369,177 +94,11 @@ public function setParent(?ClassInformationTransfer $parent = null) /** * @return \SprykerSdk\Integrator\Transfer\ClassInformationTransfer|null */ - public function getParent(): ?TransferClassInformationTransfer + public function getParent(): ?ClassInformationTransfer { return $this->parent; } - /** - * @return static - */ - public function getParentOrFail() - { - if ($this->parent === null) { - $this->throwNullValueException(static::PARENT); - } - - return $this->parent; - } - - /** - * @return $this - */ - public function requireParent() - { - $this->assertPropertyIsSet(static::PARENT); - - return $this; - } - - /** - * @param array|null $classTokenTree - * - * @return $this - */ - public function setClassTokenTree(?array $classTokenTree = null) - { - if ($classTokenTree === null) { - $classTokenTree = []; - } - - $this->classTokenTree = $classTokenTree; - $this->modifiedProperties[static::CLASS_TOKEN_TREE] = true; - - return $this; - } - - /** - * @return array - */ - public function getClassTokenTree(): array - { - return $this->classTokenTree; - } - - /** - * @param mixed $astData - * - * @return $this - */ - public function addAstData($astData) - { - $this->classTokenTree[] = $astData; - $this->modifiedProperties[static::CLASS_TOKEN_TREE] = true; - - return $this; - } - - /** - * @return $this - */ - public function requireClassTokenTree() - { - $this->assertPropertyIsSet(static::CLASS_TOKEN_TREE); - - return $this; - } - - /** - * @param array|null $originalClassTokenTree - * - * @return $this - */ - public function setOriginalClassTokenTree(?array $originalClassTokenTree = null) - { - if ($originalClassTokenTree === null) { - $originalClassTokenTree = []; - } - - $this->originalClassTokenTree = $originalClassTokenTree; - $this->modifiedProperties[static::ORIGINAL_CLASS_TOKEN_TREE] = true; - - return $this; - } - - /** - * @return array - */ - public function getOriginalClassTokenTree(): array - { - return $this->originalClassTokenTree; - } - - /** - * @param mixed $originalAstData - * - * @return $this - */ - public function addOriginalAstData($originalAstData) - { - $this->originalClassTokenTree[] = $originalAstData; - $this->modifiedProperties[static::ORIGINAL_CLASS_TOKEN_TREE] = true; - - return $this; - } - - /** - * @return $this - */ - public function requireOriginalClassTokenTree() - { - $this->assertPropertyIsSet(static::ORIGINAL_CLASS_TOKEN_TREE); - - return $this; - } - - /** - * @param array|null $tokens - * - * @return $this - */ - public function setTokens(?array $tokens = null) - { - if ($tokens === null) { - $tokens = []; - } - - $this->tokens = $tokens; - $this->modifiedProperties[static::TOKENS] = true; - - return $this; - } - - /** - * @return array - */ - public function getTokens(): array - { - return $this->tokens; - } - - /** - * @param mixed $token - * - * @return $this - */ - public function addToken($token) - { - $this->tokens[] = $token; - $this->modifiedProperties[static::TOKENS] = true; - - return $this; - } - - /** - * @return $this - */ - public function requireTokens() - { - $this->assertPropertyIsSet(static::TOKENS); - - return $this; - } - /** * @param \ArrayObject $methods * @@ -548,7 +107,6 @@ public function requireTokens() public function setMethods(ArrayObject $methods) { $this->methods = $methods; - $this->modifiedProperties[static::METHODS] = true; return $this; } @@ -569,349 +127,10 @@ public function getMethods(): ArrayObject public function addMethod(MethodInformationTransfer $method) { $this->methods[] = $method; - $this->modifiedProperties[static::METHODS] = true; return $this; } - /** - * @return $this - */ - public function requireMethods() - { - $this->assertCollectionPropertyIsSet(static::METHODS); - - return $this; - } - - /** - * @param array $data - * @param bool $ignoreMissingProperty - * - * @throws \InvalidArgumentException - * - * @return $this - */ - public function fromArray(array $data, bool $ignoreMissingProperty = false) - { - foreach ($data as $property => $value) { - $normalizedPropertyName = $this->transferPropertyNameMap[$property] ?? ''; - - switch ($normalizedPropertyName) { - case 'fullyQualifiedClassName': - case 'className': - case 'filePath': - case 'classTokenTree': - case 'originalClassTokenTree': - case 'tokens': - $this->$normalizedPropertyName = $value; - $this->modifiedProperties[$normalizedPropertyName] = true; - - break; - case 'parent': - if (is_array($value)) { - $type = $this->transferMetadata[$normalizedPropertyName]['type']; - $value = (new $type())->fromArray($value, $ignoreMissingProperty); - } - - if ($this->isPropertyStrict($normalizedPropertyName)) { - $this->assertInstanceOfTransfer($normalizedPropertyName, $value); - } - $this->$normalizedPropertyName = $value; - $this->modifiedProperties[$normalizedPropertyName] = true; - - break; - case 'methods': - $elementType = $this->transferMetadata[$normalizedPropertyName]['type']; - $this->$normalizedPropertyName = $this->processArrayObject($elementType, $value, $ignoreMissingProperty); - $this->modifiedProperties[$normalizedPropertyName] = true; - - break; - default: - if (!$ignoreMissingProperty) { - throw new InvalidArgumentException(sprintf('Missing property `%s` in `%s`', $property, static::class)); - } - } - } - - return $this; - } - - /** - * @param bool $isRecursive - * @param bool $camelCasedKeys - * - * @return array - */ - public function modifiedToArray(bool $isRecursive = true, bool $camelCasedKeys = false): array - { - if ($isRecursive && !$camelCasedKeys) { - return $this->modifiedToArrayRecursiveNotCamelCased(); - } - if ($isRecursive && $camelCasedKeys) { - return $this->modifiedToArrayRecursiveCamelCased(); - } - if (!$isRecursive && $camelCasedKeys) { - return $this->modifiedToArrayNotRecursiveCamelCased(); - } - if (!$isRecursive && !$camelCasedKeys) { - return $this->modifiedToArrayNotRecursiveNotCamelCased(); - } - - return []; - } - - /** - * @param bool $isRecursive - * @param bool $camelCasedKeys - * - * @return array - */ - public function toArray(bool $isRecursive = true, bool $camelCasedKeys = false): array - { - if ($isRecursive && !$camelCasedKeys) { - return $this->toArrayRecursiveNotCamelCased(); - } - if ($isRecursive && $camelCasedKeys) { - return $this->toArrayRecursiveCamelCased(); - } - if (!$isRecursive && !$camelCasedKeys) { - return $this->toArrayNotRecursiveNotCamelCased(); - } - if (!$isRecursive && $camelCasedKeys) { - return $this->toArrayNotRecursiveCamelCased(); - } - - return []; - } - - /** - * @param mixed $value - * @param bool $isRecursive - * @param bool $camelCasedKeys - * - * @return array - */ - protected function addValuesToCollectionModified($value, bool $isRecursive, bool $camelCasedKeys): array - { - $result = []; - foreach ($value as $elementKey => $arrayElement) { - if ($arrayElement instanceof AbstractTransfer) { - $result[$elementKey] = $arrayElement->modifiedToArray($isRecursive, $camelCasedKeys); - - continue; - } - $result[$elementKey] = $arrayElement; - } - - return $result; - } - - /** - * @param mixed $value - * @param bool $isRecursive - * @param bool $camelCasedKeys - * - * @return array - */ - protected function addValuesToCollection($value, bool $isRecursive, bool $camelCasedKeys): array - { - $result = []; - foreach ($value as $elementKey => $arrayElement) { - if ($arrayElement instanceof AbstractTransfer) { - $result[$elementKey] = $arrayElement->toArray($isRecursive, $camelCasedKeys); - - continue; - } - $result[$elementKey] = $arrayElement; - } - - return $result; - } - - /** - * @return array - */ - public function modifiedToArrayRecursiveCamelCased(): array - { - $values = []; - foreach ($this->modifiedProperties as $property => $_) { - $value = $this->$property; - - $arrayKey = $property; - - if ($value instanceof AbstractTransfer) { - $values[$arrayKey] = $value->modifiedToArray(true, true); - - continue; - } - switch ($property) { - case 'fullyQualifiedClassName': - case 'className': - case 'filePath': - case 'classTokenTree': - case 'originalClassTokenTree': - case 'parent': - $values[$arrayKey] = $value; - - break; - case 'methods': - $values[$arrayKey] = $value ? $this->addValuesToCollectionModified($value, true, true) : $value; - - break; - } - } - - return $values; - } - - /** - * @return array - */ - public function modifiedToArrayRecursiveNotCamelCased(): array - { - $values = []; - foreach ($this->modifiedProperties as $property => $_) { - $value = $this->$property; - - $arrayKey = $this->transferMetadata[$property]['name_underscore']; - - if ($value instanceof AbstractTransfer) { - $values[$arrayKey] = $value->modifiedToArray(true, false); - - continue; - } - switch ($property) { - case 'fullyQualifiedClassName': - case 'className': - case 'filePath': - case 'classTokenTree': - case 'originalClassTokenTree': - case 'tokens': - case 'parent': - $values[$arrayKey] = $value; - - break; - case 'methods': - $values[$arrayKey] = $value ? $this->addValuesToCollectionModified($value, true, false) : $value; - - break; - } - } - - return $values; - } - - /** - * @return array - */ - public function modifiedToArrayNotRecursiveNotCamelCased(): array - { - $values = []; - foreach ($this->modifiedProperties as $property => $_) { - $value = $this->$property; - - $arrayKey = $this->transferMetadata[$property]['name_underscore']; - - $values[$arrayKey] = $value; - } - - return $values; - } - - /** - * @return array - */ - public function modifiedToArrayNotRecursiveCamelCased(): array - { - $values = []; - foreach ($this->modifiedProperties as $property => $_) { - $value = $this->$property; - - $arrayKey = $property; - - $values[$arrayKey] = $value; - } - - return $values; - } - - /** - * @return void - */ - protected function initCollectionProperties(): void - { - $this->methods = new ArrayObject(); - } - - /** - * @return array - */ - public function toArrayNotRecursiveCamelCased(): array - { - return [ - 'fullyQualifiedClassName' => $this->fullyQualifiedClassName, - 'className' => $this->className, - 'filePath' => $this->filePath, - 'classTokenTree' => $this->classTokenTree, - 'originalClassTokenTree' => $this->originalClassTokenTree, - 'tokens' => $this->tokens, - 'parent' => $this->parent, - 'methods' => $this->methods, - ]; - } - - /** - * @return array - */ - public function toArrayNotRecursiveNotCamelCased(): array - { - return [ - 'fully_qualified_class_name' => $this->fullyQualifiedClassName, - 'class_name' => $this->className, - 'file_path' => $this->filePath, - 'class_token_tree' => $this->classTokenTree, - 'original_class_token_tree' => $this->originalClassTokenTree, - 'tokens' => $this->tokens, - 'parent' => $this->parent, - 'methods' => $this->methods, - ]; - } - - /** - * @return array - */ - public function toArrayRecursiveNotCamelCased(): array - { - return [ - 'fully_qualified_class_name' => $this->fullyQualifiedClassName, - 'class_name' => $this->className, - 'file_path' => $this->filePath, - 'class_token_tree' => $this->classTokenTree, - 'original_class_token_tree' => $this->originalClassTokenTree, - 'tokens' => $this->tokens, - 'parent' => $this->parent, - 'methods' => $this->addValuesToCollection($this->methods, true, false), - ]; - } - - /** - * @return array - */ - public function toArrayRecursiveCamelCased(): array - { - return [ - 'fullyQualifiedClassName' => $this->fullyQualifiedClassName, - 'className' => $this->className, - 'filePath' => $this->filePath, - 'classTokenTree' => $this->classTokenTree, - 'originalClassTokenTree' => $this->originalClassTokenTree, - 'tokens' => $this->tokens, - 'parent' => $this->parent, - 'methods' => $this->addValuesToCollection($this->methods, true, true), - ]; - } - /** * @return array */ diff --git a/src/Transfer/ExtractedValueTransfer.php b/src/Transfer/ExtractedValueTransfer.php new file mode 100644 index 00000000..30922865 --- /dev/null +++ b/src/Transfer/ExtractedValueTransfer.php @@ -0,0 +1,64 @@ +value = $value; + $this->isLiteral = $isLiteral; + $this->source = $source; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + /** + * @return bool + */ + public function isLiteral(): bool + { + return $this->isLiteral; + } + + /** + * @return bool + */ + public function isSource(): bool + { + return $this->source; + } +} diff --git a/src/Transfer/FileInformationTransfer.php b/src/Transfer/FileInformationTransfer.php new file mode 100644 index 00000000..94a4cb90 --- /dev/null +++ b/src/Transfer/FileInformationTransfer.php @@ -0,0 +1,172 @@ +filePath = $filePath; + + return $this; + } + + /** + * @return string|null + */ + public function getFilePath(): ?string + { + return $this->filePath; + } + + /** + * @return string + */ + public function getFilePathOrFail(): string + { + if ($this->filePath === null) { + $this->throwNullValueException('filePath'); + } + + return $this->filePath; + } + + /** + * @return string|null + */ + public function getContent(): ?string + { + return $this->content; + } + + /** + * @param string|null $content + * + * @return void + */ + public function setContent(?string $content): void + { + $this->content = $content; + } + + /** + * @param array|null $tokenTree + * + * @return $this + */ + public function setTokenTree(?array $tokenTree = null) + { + if ($tokenTree === null) { + $tokenTree = []; + } + + $this->tokenTree = $tokenTree; + + return $this; + } + + /** + * @return array + */ + public function getTokenTree(): array + { + return $this->tokenTree; + } + + /** + * @param array|null $originalTokenTree + * + * @return $this + */ + public function setOriginalTokenTree(?array $originalTokenTree = null) + { + if ($originalTokenTree === null) { + $originalTokenTree = []; + } + + $this->originalTokenTree = $originalTokenTree; + + return $this; + } + + /** + * @return array + */ + public function getOriginalTokenTree(): array + { + return $this->originalTokenTree; + } + + /** + * @param array|null $tokens + * + * @return $this + */ + public function setTokens(?array $tokens = null) + { + if ($tokens === null) { + $tokens = []; + } + + $this->tokens = $tokens; + + return $this; + } + + /** + * @return array + */ + public function getTokens(): array + { + return $this->tokens; + } + + /** + * @param mixed $token + * + * @return $this + */ + public function addToken($token) + { + $this->tokens[] = $token; + + return $this; + } +} diff --git a/tests/SprykerSdkTest/Integrator/BaseTestCase.php b/tests/SprykerSdkTest/Integrator/BaseTestCase.php index 9b681c1d..041664da 100755 --- a/tests/SprykerSdkTest/Integrator/BaseTestCase.php +++ b/tests/SprykerSdkTest/Integrator/BaseTestCase.php @@ -154,8 +154,8 @@ protected function createClassInformationTransfer(string $className, string $fil $originalSyntaxTree = $parser->parse(file_get_contents($filePath)); $syntaxTree = $this->traverseOriginalSyntaxTree($originalSyntaxTree); - $classInformationTransfer->setClassTokenTree($syntaxTree) - ->setOriginalClassTokenTree($originalSyntaxTree); + $classInformationTransfer->setTokenTree($syntaxTree) + ->setOriginalTokenTree($originalSyntaxTree); return $classInformationTransfer; } diff --git a/tests/SprykerSdkTest/Integrator/Builder/ClassLoader/ClassLoaderTest.php b/tests/SprykerSdkTest/Integrator/Builder/ClassLoader/ClassLoaderTest.php index 00daca1f..193abc59 100644 --- a/tests/SprykerSdkTest/Integrator/Builder/ClassLoader/ClassLoaderTest.php +++ b/tests/SprykerSdkTest/Integrator/Builder/ClassLoader/ClassLoaderTest.php @@ -54,7 +54,7 @@ public function testLoadClassWithNotExistingFile(): void $this->assertNull($transfer->getParent()); $this->assertNull($transfer->getFilePath()); $this->assertSame([], $transfer->getTokens()); - $this->assertSame([], $transfer->getOriginalClassTokenTree()); + $this->assertSame([], $transfer->getOriginalTokenTree()); } /**