Skip to content

Commit

Permalink
Merge branch '1.14.x' into 2.0.x
Browse files Browse the repository at this point in the history
* 1.14.x:
  Allow annotation classes with a variadic parameter (#479)
  • Loading branch information
derrabus committed Feb 2, 2023
2 parents 508c71c + fb0d71a commit e157ef3
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 0 deletions.
21 changes: 21 additions & 0 deletions lib/Doctrine/Common/Annotations/DocParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,10 @@ class_exists(NamedArgumentConstructor::class);
$metadata['default_property'] = reset($metadata['properties']);
} elseif ($metadata['has_named_argument_constructor']) {
foreach ($constructor->getParameters() as $parameter) {
if ($parameter->isVariadic()) {
break;
}

$metadata['constructor_args'][$parameter->getName()] = [
'position' => $parameter->getPosition(),
'default' => $parameter->isOptional() ? $parameter->getDefaultValue() : null,
Expand Down Expand Up @@ -930,6 +934,23 @@ private function Annotation()

if (self::$annotationMetadata[$name]['has_named_argument_constructor']) {
if (PHP_VERSION_ID >= 80000) {
foreach ($values as $property => $value) {
if (! isset(self::$annotationMetadata[$name]['constructor_args'][$property])) {
throw AnnotationException::creationError(sprintf(
<<<'EXCEPTION'
The annotation @%s declared on %s does not have a property named "%s"
that can be set through its named arguments constructor.
Available named arguments: %s
EXCEPTION
,
$originalName,
$this->context,
$property,
implode(', ', array_keys(self::$annotationMetadata[$name]['constructor_args']))
));
}
}

return $this->instantiateAnnotiation($originalName, $this->context, $name, $values);
}

Expand Down
140 changes: 140 additions & 0 deletions tests/Doctrine/Tests/Common/Annotations/DocParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,18 @@ public function testNamedArgumentsConstructorAnnotationWithDefaultProperty(): vo
self::assertSame(1234, $result[0]->getBar());
}

public function testNamedArgumentsConstructorAnnotationWithExtraArguments(): void
{
$docParser = $this->createTestParser();

$this->expectException(AnnotationException::class);
$this->expectExceptionMessageMatches(
'/does not have a property named "invalid"\s.*\sAvailable named arguments: foo, bar/'
);

$docParser->parse('/** @AnotherNamedAnnotation(foo="baz", invalid="uh oh") */');
}

public function testNamedArgumentsConstructorAnnotationWithDefaultPropertyAsArray(): void
{
$result = $this
Expand Down Expand Up @@ -1701,6 +1713,115 @@ public function testNamedArgumentsConstructorAnnotationWithWrongArgumentType():
}
}

public function testAnnotationWithConstructorWithVariadicParamAndExtraNamedArguments(): void
{
$parser = $this->createTestParser();
$docblock = <<<'DOCBLOCK'
/**
* @SomeAnnotationWithConstructorWithVariadicParam(name = "Some data", foo = "Foo", bar = "Bar")
*/
DOCBLOCK;

$this->expectException(AnnotationException::class);
$this->expectExceptionMessageMatches(
'/does not have a property named "foo"\s.*\sAvailable named arguments: name/'
);

$parser->parse($docblock);
}

public function testAnnotationWithConstructorWithVariadicParamAndExtraNamedArgumentsShuffled(): void
{
$parser = $this->createTestParser();
$docblock = <<<'DOCBLOCK'
/**
* @SomeAnnotationWithConstructorWithVariadicParam(foo = "Foo", name = "Some data", bar = "Bar")
*/
DOCBLOCK;

$this->expectException(AnnotationException::class);
$this->expectExceptionMessageMatches(
'/does not have a property named "foo"\s.*\sAvailable named arguments: name/'
);

$parser->parse($docblock);
}

public function testAnnotationWithConstructorWithVariadicParamAndCombinedNamedAndPositionalArguments(): void
{
$parser = $this->createTestParser();
$docblock = <<<'DOCBLOCK'
/**
* @SomeAnnotationWithConstructorWithVariadicParam("Some data", "Foo", bar = "Bar")
*/
DOCBLOCK;

$this->expectException(AnnotationException::class);
$this->expectExceptionMessageMatches(
'/does not have a property named "bar"\s.*\sAvailable named arguments: name/'
);

$parser->parse($docblock);
}

public function testAnnotationWithConstructorWithVariadicParamPassOneNamedArgument(): void
{
$parser = $this->createTestParser();
$docblock = <<<'DOCBLOCK'
/**
* @SomeAnnotationWithConstructorWithVariadicParam(name = "Some data", data = "Foo")
*/
DOCBLOCK;

$this->expectException(AnnotationException::class);
$this->expectExceptionMessageMatches(
'/does not have a property named "data"\s.*\sAvailable named arguments: name/'
);

$parser->parse($docblock);
}

public function testAnnotationWithConstructorWithVariadicParamPassPositionalArguments(): void
{
$parser = $this->createTestParser();
$docblock = <<<'DOCBLOCK'
/**
* @SomeAnnotationWithConstructorWithVariadicParam("Some data", "Foo", "Bar")
*/
DOCBLOCK;

$result = $parser->parse($docblock);
self::assertCount(1, $result);
$annot = $result[0];

self::assertInstanceOf(SomeAnnotationWithConstructorWithVariadicParam::class, $annot);

self::assertSame('Some data', $annot->name);
// Positional extra arguments will be ignored
self::assertSame([], $annot->data);
}

public function testAnnotationWithConstructorWithVariadicParamNoArgs(): void
{
$parser = $this->createTestParser();

// Without variadic arguments
$docblock = <<<'DOCBLOCK'
/**
* @SomeAnnotationWithConstructorWithVariadicParam("Some data")
*/
DOCBLOCK;

$result = $parser->parse($docblock);
self::assertCount(1, $result);
$annot = $result[0];

self::assertInstanceOf(SomeAnnotationWithConstructorWithVariadicParam::class, $annot);

self::assertSame('Some data', $annot->name);
self::assertSame([], $annot->data);
}

/**
* Override for BC with PHPUnit <8
*/
Expand Down Expand Up @@ -1782,6 +1903,25 @@ public function getBar(): int
}
}

/**
* @Annotation
* @NamedArgumentConstructor
*/
class SomeAnnotationWithConstructorWithVariadicParam
{
public function __construct(string $name, string ...$data)
{
$this->name = $name;
$this->data = $data;
}

/** @var string[] */
public $data;

/** @var string */
public $name;
}

/** @Annotation */
class SettingsAnnotation
{
Expand Down

0 comments on commit e157ef3

Please sign in to comment.