diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index aec538b45..ec1ea0730 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -149,7 +149,11 @@ jobs: composer-options: "--no-scripts --working-dir=tools/twigcs" - name: "Install PHPUnit" - run: vendor/bin/simple-phpunit install + run: | + if [[ ${{ matrix.dependency_versions == 'lowest' }} ]]; then + echo "SYMFONY_PHPUNIT_REQUIRE=nikic/php-parser:^4.18" >> $GITHUB_ENV + fi + vendor/bin/simple-phpunit install - name: "PHPUnit version" run: vendor/bin/simple-phpunit --version diff --git a/composer.json b/composer.json index a88c9ff0f..ef29c3a3b 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "require": { "php": ">=8.1", "doctrine/inflector": "^2.0", - "nikic/php-parser": "^4.11", + "nikic/php-parser": "^4.18|^5.0", "symfony/config": "^6.3|^7.0", "symfony/console": "^6.3|^7.0", "symfony/dependency-injection": "^6.3|^7.0", diff --git a/src/Security/SecurityControllerBuilder.php b/src/Security/SecurityControllerBuilder.php index d28b79ad0..5c74a0f85 100644 --- a/src/Security/SecurityControllerBuilder.php +++ b/src/Security/SecurityControllerBuilder.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\MakerBundle\Security; +use PhpParser\Builder\Param; use Symfony\Bundle\MakerBundle\Util\ClassSourceManipulator; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -32,7 +33,7 @@ public function addLoginMethod(ClassSourceManipulator $manipulator): void $manipulator->addUseStatementIfNecessary(AuthenticationUtils::class); $loginMethodBuilder->addParam( - (new \PhpParser\Builder\Param('authenticationUtils'))->setTypeHint('AuthenticationUtils') + (new Param('authenticationUtils'))->setType('AuthenticationUtils') ); $manipulator->addMethodBody($loginMethodBuilder, <<<'CODE' diff --git a/src/Util/ClassSourceManipulator.php b/src/Util/ClassSourceManipulator.php index 6a9d86d93..833b80dcb 100644 --- a/src/Util/ClassSourceManipulator.php +++ b/src/Util/ClassSourceManipulator.php @@ -28,6 +28,7 @@ use PhpParser\NodeTraverser; use PhpParser\NodeVisitor; use PhpParser\Parser; +use PhpParser\PhpVersion; use Symfony\Bundle\MakerBundle\ConsoleStyle; use Symfony\Bundle\MakerBundle\Doctrine\BaseCollectionRelation; use Symfony\Bundle\MakerBundle\Doctrine\BaseRelation; @@ -48,7 +49,7 @@ final class ClassSourceManipulator private const CONTEXT_CLASS_METHOD = 'class_method'; private const DEFAULT_VALUE_NONE = '__default_value_none'; - private Parser\Php7 $parser; + private Parser $parser; private Lexer\Emulative $lexer; private PrettyPrinter $printer; private ?ConsoleStyle $io = null; @@ -64,14 +65,22 @@ public function __construct( private bool $overwrite = false, private bool $useAttributesForDoctrineMapping = true, ) { - $this->lexer = new Lexer\Emulative([ - 'usedAttributes' => [ - 'comments', - 'startLine', 'endLine', - 'startTokenPos', 'endTokenPos', - ], - ]); - $this->parser = new Parser\Php7($this->lexer); + /* @legacy Support for nikic/php-parser v4 */ + if (class_exists(PhpVersion::class)) { + $version = PhpVersion::fromString(\PHP_VERSION); + $this->lexer = new Lexer\Emulative($version); + $this->parser = new Parser\Php8($this->lexer, $version); + } else { + $this->lexer = new Lexer\Emulative([ + 'usedAttributes' => [ + 'comments', + 'startLine', 'endLine', + 'startTokenPos', 'endTokenPos', + ], + ]); + $this->parser = new Parser\Php7($this->lexer); + } + $this->printer = new PrettyPrinter(); $this->setSourceCode($sourceCode); @@ -327,7 +336,7 @@ public function createMethodBuilder(string $methodName, $returnType, bool $isRet if (class_exists($returnType) || interface_exists($returnType)) { $returnType = $this->addUseStatementIfNecessary($returnType); } - $methodNodeBuilder->setReturnType($isReturnTypeNullable ? new Node\NullableType($returnType) : $returnType); + $methodNodeBuilder->setReturnType($isReturnTypeNullable ? new Node\NullableType(new Node\Identifier($returnType)) : $returnType); } if ($commentLines) { @@ -414,7 +423,7 @@ private function addCustomGetter(string $propertyName, string $methodName, $retu ); if (null !== $returnType) { - $getterNodeBuilder->setReturnType($isReturnTypeNullable ? new Node\NullableType($returnType) : $returnType); + $getterNodeBuilder->setReturnType($isReturnTypeNullable ? new Node\NullableType(new Node\Identifier($returnType)) : $returnType); } if ($commentLines) { @@ -435,7 +444,7 @@ private function createSetterNodeBuilder(string $propertyName, $type, bool $isNu $paramBuilder = new Builder\Param($propertyName); if (null !== $type) { - $paramBuilder->setType($isNullable ? new Node\NullableType($type) : $type); + $paramBuilder->setType($isNullable ? new Node\NullableType(new Node\Identifier($type)) : $type); } $setterNodeBuilder->addParam($paramBuilder->getNode()); @@ -641,7 +650,7 @@ private function addCollectionRelation(BaseCollectionRelation $relation): void $removerNodeBuilder = (new Builder\Method($relation->getRemoverMethodName()))->makePublic(); $paramBuilder = new Builder\Param($argName); - $paramBuilder->setTypeHint($typeHint); + $paramBuilder->setType($typeHint); $removerNodeBuilder->addParam($paramBuilder->getNode()); // $this->avatars->removeElement($avatar) @@ -841,7 +850,7 @@ public function buildAttributeNode(string $attributeClass, array $options, strin $context = $this; $nodeArguments = array_map(static function (string $option, mixed $value) use ($context) { if (null === $value) { - return new Node\NullableType($option); + return new Node\NullableType(new Node\Identifier($option)); } // Use the Doctrine Types constant @@ -900,7 +909,13 @@ private function setSourceCode(string $sourceCode): void { $this->sourceCode = $sourceCode; $this->oldStmts = $this->parser->parse($sourceCode); - $this->oldTokens = $this->lexer->getTokens(); + + /* @legacy Support for nikic/php-parser v4 */ + if (\is_callable([$this->parser, 'getTokens'])) { + $this->oldTokens = $this->parser->getTokens(); + } elseif (\is_callable([$this->lexer, 'getTokens'])) { + $this->oldTokens = $this->lexer->getTokens(); + } $traverser = new NodeTraverser(); $traverser->addVisitor(new NodeVisitor\CloningVisitor()); diff --git a/src/Util/PrettyPrinter.php b/src/Util/PrettyPrinter.php index 59b6fbcbc..9b93dbfbd 100644 --- a/src/Util/PrettyPrinter.php +++ b/src/Util/PrettyPrinter.php @@ -52,7 +52,7 @@ protected function setIndentLevel(int $level): void * After * public function getFoo(): string */ - protected function pStmt_ClassMethod(Stmt\ClassMethod $node) + protected function pStmt_ClassMethod(Stmt\ClassMethod $node): string { $classMethod = parent::pStmt_ClassMethod($node); diff --git a/tests/Util/ClassSourceManipulatorTest.php b/tests/Util/ClassSourceManipulatorTest.php index a32d40b38..737a69b63 100644 --- a/tests/Util/ClassSourceManipulatorTest.php +++ b/tests/Util/ClassSourceManipulatorTest.php @@ -698,7 +698,7 @@ public function testAddMethodWithBody(): void $methodBuilder = $manipulator->createMethodBuilder('action', 'JsonResponse', false, ['@Route("/action", name="app_action")']); $methodBuilder->addParam( - (new Param('param'))->setTypeHint('string') + (new Param('param'))->setType('string') ); $manipulator->addMethodBody($methodBuilder, <<<'CODE'