Skip to content

Commit

Permalink
Compability with PhpParser v5
Browse files Browse the repository at this point in the history
  • Loading branch information
Korbeil committed Jan 11, 2024
1 parent d02c3b6 commit 456eea4
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed
- [GH#27](https://github.com/jolicode/automapper/pull/27) Use PhpStanExtractor instead of PhpDocExtractor
- [GH#31](https://github.com/jolicode/automapper/pull/31) Compability with PhpParser v5

## [8.1.0] - 2023-12-14
### Added
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"require": {
"php": "^8.2",
"doctrine/inflector": "^1.4 || ^2.0",
"nikic/php-parser": "^4.0",
"nikic/php-parser": "^4.0 || ^5.0",
"symfony/property-info": "^5.4 || ^6.0 || ^7.0",
"symfony/serializer": "^5.4 || ^6.0 || ^7.0"
},
Expand Down
5 changes: 3 additions & 2 deletions src/AutoMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
use AutoMapper\Transformer\TransformerFactoryInterface;
use AutoMapper\Transformer\UniqueTypeTransformerFactory;
use Doctrine\Common\Annotations\AnnotationReader;
use PhpParser\ParserFactory;
use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
Expand All @@ -45,6 +44,8 @@
*/
class AutoMapper implements AutoMapperInterface, AutoMapperRegistryInterface, MapperGeneratorMetadataRegistryInterface
{
use PhpParserHelper;

public const VERSION = '8.2.0-DEV';
public const VERSION_ID = 80200;
public const MAJOR_VERSION = 8;
Expand Down Expand Up @@ -179,7 +180,7 @@ public static function create(
$loader = new EvalLoader(
new Generator(
new ClassMethodToCallbackExtractor(),
(new ParserFactory())->create(ParserFactory::PREFER_PHP7),
self::getParser(),
new ClassDiscriminatorFromClassMetadata($classMetadataFactory),
$allowReadOnlyTargetToPopulate
)
Expand Down
16 changes: 12 additions & 4 deletions src/Extractor/ClassMethodToCallbackExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
use AutoMapper\Exception\InvalidArgumentException;
use AutoMapper\Exception\LogicException;
use AutoMapper\Exception\RuntimeException;
use AutoMapper\PhpParserHelper;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt;
use PhpParser\Parser;
use PhpParser\ParserFactory;

/**
* Extracts the code of the given method from a given class and wraps it inside a closure, in order to inject it
Expand All @@ -26,11 +27,13 @@
*/
final readonly class ClassMethodToCallbackExtractor
{
use PhpParserHelper;

private Parser $parser;

public function __construct(?Parser $parser = null)
{
$this->parser = $parser ?? (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
$this->parser = $parser ?? self::getParser();
}

/**
Expand Down Expand Up @@ -66,15 +69,20 @@ public function extract(string $class, string $method, array $inputParameters):
$closureParameters = [];
foreach ($classMethod->getParams() as $parameter) {
if ($parameter->var instanceof Expr\Variable && $parameter->type instanceof Identifier) {
$closureParameters[] = new Param(new Expr\Variable($parameter->var->name), type: $parameter->type->name);
$closureParameters[] = new Param(new Expr\Variable($parameter->var->name), type: new Name($parameter->type->name));
}
}

$returnType = $classMethod->returnType;
if (\is_string($returnType)) {

Check failure on line 77 in src/Extractor/ClassMethodToCallbackExtractor.php

View workflow job for this annotation

GitHub Actions / phpstan

Call to function is_string() with PhpParser\Node\ComplexType|PhpParser\Node\Identifier|PhpParser\Node\Name|null will always evaluate to false.

Check failure on line 77 in src/Extractor/ClassMethodToCallbackExtractor.php

View workflow job for this annotation

GitHub Actions / phpstan

Call to function is_string() with PhpParser\Node\ComplexType|PhpParser\Node\Identifier|PhpParser\Node\Name|null will always evaluate to false.
$returnType = new Name($returnType);
}

return new Expr\FuncCall(
new Expr\Closure([

Check failure on line 82 in src/Extractor/ClassMethodToCallbackExtractor.php

View workflow job for this annotation

GitHub Actions / phpstan

Parameter #1 $subNodes of class PhpParser\Node\Expr\Closure constructor expects array{static?: bool, byRef?: bool, params?: array<PhpParser\Node\Param>, uses?: array<PhpParser\Node\ClosureUse>, returnType?: PhpParser\Node\ComplexType|PhpParser\Node\Identifier|PhpParser\Node\Name|null, stmts?: array<PhpParser\Node\Stmt>, attrGroups?: array<PhpParser\Node\AttributeGroup>}, array{stmts: array<PhpParser\Node\Stmt>|null, params: array<int<0, max>, PhpParser\Node\Param>, returnType: PhpParser\Node\ComplexType|PhpParser\Node\Identifier|PhpParser\Node\Name|null} given.

Check failure on line 82 in src/Extractor/ClassMethodToCallbackExtractor.php

View workflow job for this annotation

GitHub Actions / phpstan

Parameter #1 $subNodes of class PhpParser\Node\Expr\Closure constructor expects array{static?: bool, byRef?: bool, params?: array<PhpParser\Node\Param>, uses?: array<PhpParser\Node\ClosureUse>, returnType?: PhpParser\Node\ComplexType|PhpParser\Node\Identifier|PhpParser\Node\Name|null, stmts?: array<PhpParser\Node\Stmt>, attrGroups?: array<PhpParser\Node\AttributeGroup>}, array{stmts: array<PhpParser\Node\Stmt>|null, params: array<int<0, max>, PhpParser\Node\Param>, returnType: PhpParser\Node\ComplexType|PhpParser\Node\Identifier|PhpParser\Node\Name|null} given.
'stmts' => $classMethod->stmts,
'params' => $closureParameters,
'returnType' => $classMethod->returnType,
'returnType' => $returnType,
]),
$inputParameters,
);
Expand Down
28 changes: 16 additions & 12 deletions src/Generator/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@
use AutoMapper\GeneratedMapper;
use AutoMapper\MapperContext;
use AutoMapper\MapperGeneratorMetadataInterface;
use AutoMapper\PhpParserHelper;
use AutoMapper\Transformer\AssignedByReferenceTransformerInterface;
use AutoMapper\Transformer\DependentTransformerInterface;
use AutoMapper\Transformer\TransformerInterface;
use PhpParser\Modifiers;
use PhpParser\Node\Arg;
use PhpParser\Node\ArrayItem;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;
use PhpParser\Parser;
use PhpParser\ParserFactory;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface;

/**
Expand All @@ -32,6 +34,8 @@
*/
final readonly class Generator
{
use PhpParserHelper;

private Parser $parser;

public function __construct(
Expand All @@ -40,7 +44,7 @@ public function __construct(
private ?ClassDiscriminatorResolverInterface $classDiscriminator = null,
private bool $allowReadOnlyTargetToPopulate = false,
) {
$this->parser = $parser ?? (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
$this->parser = $parser ?? self::getParser();
}

/**
Expand Down Expand Up @@ -353,7 +357,7 @@ public function generate(MapperGeneratorMetadataInterface $mapperGeneratorMetada
new Expr\Array_()
)),
new Arg(new Expr\Array_(array_map(function (string $group) {
return new Expr\ArrayItem(new Scalar\String_($group));
return new ArrayItem(new Scalar\String_($group));
}, $propertyMapping->sourceGroups))),
])
);
Expand All @@ -379,7 +383,7 @@ public function generate(MapperGeneratorMetadataInterface $mapperGeneratorMetada
new Expr\Array_()
)),
new Arg(new Expr\Array_(array_map(function (string $group) {
return new Expr\ArrayItem(new Scalar\String_($group));
return new ArrayItem(new Scalar\String_($group));
}, $propertyMapping->targetGroups))),
])
);
Expand All @@ -396,7 +400,7 @@ public function generate(MapperGeneratorMetadataInterface $mapperGeneratorMetada
new Expr\ArrayDimFetch($contextVariable, new Scalar\String_(MapperContext::DEPTH)),
new Expr\ConstFetch(new Name('0'))
),
new Scalar\LNumber($propertyMapping->maxDepth)
new Scalar\Int_($propertyMapping->maxDepth)
);
}

Expand Down Expand Up @@ -468,14 +472,14 @@ public function generate(MapperGeneratorMetadataInterface $mapperGeneratorMetada
* }
*/
$mapMethod = new Stmt\ClassMethod('map', [
'flags' => Stmt\Class_::MODIFIER_PUBLIC,
'flags' => Modifiers::PUBLIC,
'params' => [
new Param(new Expr\Variable($sourceInput->name)),
new Param(new Expr\Variable('context'), new Expr\Array_(), 'array'),
new Param(new Expr\Variable('context'), new Expr\Array_(), new Name('array')),
],
'byRef' => true,
'stmts' => $statements,
'returnType' => \PHP_VERSION_ID >= 80000 ? 'mixed' : null,
'returnType' => \PHP_VERSION_ID >= 80000 ? new Name('mixed') : null,
]);

/*
Expand All @@ -490,7 +494,7 @@ public function generate(MapperGeneratorMetadataInterface $mapperGeneratorMetada
* }
*/
$constructMethod = new Stmt\ClassMethod('__construct', [
'flags' => Stmt\Class_::MODIFIER_PUBLIC,
'flags' => Modifiers::PUBLIC,
'stmts' => $constructStatements,
]);

Expand All @@ -509,11 +513,11 @@ public function generate(MapperGeneratorMetadataInterface $mapperGeneratorMetada
* }
*/
$classStmts[] = new Stmt\ClassMethod('injectMappers', [
'flags' => Stmt\Class_::MODIFIER_PUBLIC,
'flags' => Modifiers::PUBLIC,
'params' => [
new Param(new Expr\Variable('autoMapperRegistry'), null, new Name\FullyQualified(AutoMapperRegistryInterface::class)),
],
'returnType' => 'void',
'returnType' => new Name('void'),
'stmts' => $injectMapperStatements,
]);
}
Expand All @@ -526,7 +530,7 @@ public function generate(MapperGeneratorMetadataInterface $mapperGeneratorMetada
* }
*/
return new Stmt\Class_($mapperGeneratorMetadata->getMapperClassName(), [
'flags' => Stmt\Class_::MODIFIER_FINAL,
'flags' => Modifiers::FINAL,
'extends' => new Name\FullyQualified(GeneratedMapper::class),
'stmts' => $classStmts,
]);
Expand Down
25 changes: 25 additions & 0 deletions src/PhpParserHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace AutoMapper;

use PhpParser\Parser;
use PhpParser\ParserFactory;

/**
* @author Baptiste Leduc <[email protected]>
*/
trait PhpParserHelper
{
public static function getParser(): Parser
{
if (method_exists(ParserFactory::class, 'create')) {
// nikic/php-parser v4
return (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
}

// nikic/php-parser v5
return (new ParserFactory())->createForHostVersion();
}
}
3 changes: 2 additions & 1 deletion src/Transformer/BuiltinTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use AutoMapper\Extractor\PropertyMapping;
use AutoMapper\Generator\UniqueVariableScope;
use PhpParser\Node\Arg;
use PhpParser\Node\ArrayItem;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Name;
Expand Down Expand Up @@ -100,7 +101,7 @@ public function transform(Expr $input, Expr $target, PropertyMapping $propertyMa

private function toArray(Expr $input): Expr
{
return new Expr\Array_([new Expr\ArrayItem($input)]);
return new Expr\Array_([new ArrayItem($input)]);
}

private function fromIteratorToArray(Expr $input): Expr
Expand Down
2 changes: 1 addition & 1 deletion tests/AutoMapperBaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected function buildAutoMapper(bool $allowReadOnlyTargetToPopulate = false,

$this->loader = new FileLoader(new Generator(
new ClassMethodToCallbackExtractor(),
(new ParserFactory())->create(ParserFactory::PREFER_PHP7),
(new ParserFactory())->createForHostVersion(),
new ClassDiscriminatorFromClassMetadata($classMetadataFactory),
$allowReadOnlyTargetToPopulate
), __DIR__ . '/cache');
Expand Down
4 changes: 2 additions & 2 deletions tests/Extractor/AstExtractorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function testExtractSimpleMethod(string $varName): void
$extractedMethod = new Expression($extractor->extract(FooCustomMapper::class, 'transform', [new Arg(new Variable($varName))]));

$this->assertEquals(<<<PHP
(function (mixed \$object) : mixed {
(function (mixed \$object): mixed {
if (\$object instanceof Foo) {
\$object->bar = 'Hello World!';
}
Expand All @@ -52,7 +52,7 @@ public function testExtractMethodWithTwoVariables(): void
$extractedMethod = new Expression($extractor->extract(FooCustomMapper::class, 'switch', [new Arg(new Variable('someVar')), new Arg(new Variable('context'))]));

$this->assertEquals(<<<PHP
(function (mixed \$object, string \$someString) : mixed {
(function (mixed \$object, string \$someString): mixed {
if (\$object instanceof Foo) {
\$object->bar = 'Hello World!';
\$object->baz = \$someString;
Expand Down

0 comments on commit 456eea4

Please sign in to comment.