From 47bd0180d17cbaa3409de909020901820d89b047 Mon Sep 17 00:00:00 2001 From: Andrii Serdiuk Date: Tue, 21 Jul 2020 01:36:57 +0300 Subject: [PATCH 1/8] [PropertyAccess] Fix accessing dynamic properties --- .../PropertyAccess/PropertyAccessor.php | 14 +++++++---- .../Fixtures/TestClassDynamicProperty.php | 11 +++++++++ .../Tests/PropertyAccessorTest.php | 24 +++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassDynamicProperty.php diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index af7331d52b..52894afaa1 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -435,10 +435,16 @@ class PropertyAccessor implements PropertyAccessorInterface throw $e; } - } elseif ($object instanceof \stdClass && property_exists($object, $property)) { - $result[self::VALUE] = $object->$property; - if (isset($zval[self::REF])) { - $result[self::REF] = &$object->$property; + } elseif (property_exists($object, $property)) { + try { + $result[self::VALUE] = $object->$property; + if (isset($zval[self::REF])) { + $result[self::REF] = &$object->$property; + } + } catch (\Error $e) { + if (!$ignoreInvalidProperty) { + throw new NoSuchPropertyException(sprintf('Can\'t read protected or private property "%s" in class "%s".', $property, $class), 0, $e); + } } } elseif (!$ignoreInvalidProperty) { throw new NoSuchPropertyException(sprintf('Can\'t get a way to read the property "%s" in class "%s".', $property, $class)); diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassDynamicProperty.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassDynamicProperty.php new file mode 100644 index 0000000000..93caeb6db2 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClassDynamicProperty.php @@ -0,0 +1,11 @@ +dynamicProperty = $dynamicProperty; + } +} diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 89e02f334d..790deb5e69 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -21,6 +21,7 @@ use Symfony\Component\PropertyAccess\Tests\Fixtures\ReturnTyped; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestAdderRemoverInvalidArgumentLength; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestAdderRemoverInvalidMethods; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClass; +use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassDynamicProperty; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassIsWritable; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicCall; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClassMagicGet; @@ -97,6 +98,29 @@ class PropertyAccessorTest extends TestCase $this->assertSame($value, $this->propertyAccessor->getValue($objectOrArray, $path)); } + /** + * Test get dynamic value from object is other than \stdClass instance. + */ + public function testGetDynamicValue() + { + $value = 'dynamicPropertyValue'; + $path = 'dynamicProperty'; + $object = new TestClassDynamicProperty($value); + + $this->assertSame($value, $this->propertyAccessor->getValue($object, $path)); + } + + /** + * Ensure exact exception with message was thrown on access to non-public property. + */ + public function testGetInaccessibleProperty() + { + $this->expectException('Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException'); + $this->expectExceptionMessage(sprintf('Can\'t read protected or private property "%s" in class "%s".', 'protectedProperty', TestClass::class)); + + $this->propertyAccessor->getValue(new TestClass('Bernhard'), 'protectedProperty'); + } + /** * @dataProvider getPathsWithMissingProperty */ From 039fc80d6c6615b611d5716eab241434763113a1 Mon Sep 17 00:00:00 2001 From: Flinsch Date: Tue, 25 Aug 2020 14:44:21 +0200 Subject: [PATCH 2/8] [TwigBridge] Fix #37931: BC break where filter method `trans` did not allow null values for `$message` parameter anymore --- src/Symfony/Bridge/Twig/Extension/TranslationExtension.php | 6 +++++- .../Twig/Tests/Extension/TranslationExtensionTest.php | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php b/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php index ad16041356..d65578608d 100644 --- a/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/TranslationExtension.php @@ -92,8 +92,12 @@ final class TranslationExtension extends AbstractExtension return $this->translationNodeVisitor ?: $this->translationNodeVisitor = new TranslationNodeVisitor(); } - public function trans(string $message, array $arguments = [], string $domain = null, string $locale = null, int $count = null): string + public function trans(?string $message, array $arguments = [], string $domain = null, string $locale = null, int $count = null): string { + if (null === $message || '' === $message) { + return ''; + } + if (null !== $count) { $arguments['%count%'] = $count; } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php index f384fa59c5..28149e1315 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php @@ -118,6 +118,10 @@ class TranslationExtensionTest extends TestCase ['{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|trans(count=count) }}', 'There is 5 apples', ['count' => 5]], ['{{ text|trans(count=5, arguments={\'%name%\': \'Symfony\'}) }}', 'There is 5 apples (Symfony)', ['text' => '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%)']], ['{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|trans({}, "messages", "fr", count) }}', 'There is 5 apples', ['count' => 5]], + + // trans filter with null message + ['{{ null|trans }}', ''], + ['{{ foo|trans }}', '', ['foo' => null]], ]; } From 17c0784c447b1e3e107874476cadaa6d25bcf3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Romey?= Date: Thu, 27 Aug 2020 14:57:37 +0200 Subject: [PATCH 3/8] Update Notifier bridge readme --- .../Component/Notifier/Bridge/Firebase/README.md | 12 ++++++++++++ .../Component/Notifier/Bridge/Mattermost/README.md | 12 ++++++++++++ .../Component/Notifier/Bridge/RocketChat/README.md | 12 ++++++++++++ .../Component/Notifier/Bridge/Sinch/README.md | 13 +++++++++++++ 4 files changed, 49 insertions(+) diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/README.md b/src/Symfony/Component/Notifier/Bridge/Firebase/README.md index 45da948c15..fc4f88a38f 100644 --- a/src/Symfony/Component/Notifier/Bridge/Firebase/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Firebase/README.md @@ -3,6 +3,18 @@ Firebase Notifier Provides Firebase integration for Symfony Notifier. +DSN example +----------- + +``` +// .env file +FIREBASE_DSN=firebase://USERNAME:PASSWORD@default +``` + +where: + - `USERNAME` is your Firebase username + - `PASSWORD` is your Firebase password + Resources --------- diff --git a/src/Symfony/Component/Notifier/Bridge/Mattermost/README.md b/src/Symfony/Component/Notifier/Bridge/Mattermost/README.md index 0ed0fc00a7..8cf29c4f18 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mattermost/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Mattermost/README.md @@ -3,6 +3,18 @@ Mattermost Notifier Provides Mattermost integration for Symfony Notifier. +DSN example +----------- + +``` +// .env file +MATTERMOST_DSN=mattermost://ACCESS_TOKEN@default?channel=CHANNEL +``` + +where: + - `ACCESS_TOKEN` is your Mattermost access token + - `CHANNEL` is your Mattermost channel + Resources --------- diff --git a/src/Symfony/Component/Notifier/Bridge/RocketChat/README.md b/src/Symfony/Component/Notifier/Bridge/RocketChat/README.md index 57916e8bff..6bec07acb6 100644 --- a/src/Symfony/Component/Notifier/Bridge/RocketChat/README.md +++ b/src/Symfony/Component/Notifier/Bridge/RocketChat/README.md @@ -3,6 +3,18 @@ RocketChat Notifier Provides RocketChat integration for Symfony Notifier. +DSN example +----------- + +``` +// .env file +ROCKETCHAT_DSN=rocketchat://ACCESS_TOKEN@default?channel=CHANNEL +``` + +where: + - `ACCESS_TOKEN` is your RocketChat access token + - `CHANNEL` is your RocketChat channel + Resources --------- diff --git a/src/Symfony/Component/Notifier/Bridge/Sinch/README.md b/src/Symfony/Component/Notifier/Bridge/Sinch/README.md index 052a981689..da9f8b8db2 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sinch/README.md +++ b/src/Symfony/Component/Notifier/Bridge/Sinch/README.md @@ -3,6 +3,19 @@ Sinch Notifier Provides Sinch integration for Symfony Notifier. +DSN example +----------- + +``` +// .env file +SINCH_DSN=sinch://SERVICE_PLAN_ID:AUTH_TOKEN@default?from=FROM +``` + +where: + - `SERVICE_PLAN_ID` is your Sinch service plan id + - `AUTH_TOKEN` is your Sinch auth token + - `FROM` is your sender + Resources --------- From 33eccd2a0070daac692b6ab9736170639c80f318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 26 Aug 2020 23:49:04 +0200 Subject: [PATCH 4/8] [PhpUnit] Add polyfill for assertMatchesRegularExpression() --- .../PhpUnit/Legacy/PolyfillTestCaseTrait.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php index cb3fbf4490..ffd3375e68 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php @@ -11,8 +11,10 @@ namespace Symfony\Bridge\PhpUnit\Legacy; +use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use SebastianBergmann\RecursionContext\InvalidArgumentException; /** * This trait is @internal. @@ -116,4 +118,18 @@ trait PolyfillTestCaseTrait $property->setAccessible(true); $property->setValue($this, $messageRegExp); } + + /** + * Asserts that a string matches a given regular expression. + * + * @param string $pattern + * @param string $string + * @param string $message + * + * @return void + */ + public function assertMatchesRegularExpression($pattern, $string, $message = '') + { + $this->assertRegExp($pattern, $string, $message); + } } From 0426113edaa41c795a20c28784634a9b91a37cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 27 Aug 2020 16:43:53 +0200 Subject: [PATCH 5/8] [PhpUnitBridge] Move assertMatchesRegularExpression in PolyfillAssertTrait --- .../PhpUnit/Legacy/PolyfillAssertTrait.php | 21 +++++++++++++++++++ .../PhpUnit/Legacy/PolyfillTestCaseTrait.php | 16 -------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillAssertTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillAssertTrait.php index 69a01d2927..646ea6b264 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillAssertTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillAssertTrait.php @@ -13,6 +13,7 @@ namespace Symfony\Bridge\PhpUnit\Legacy; use PHPUnit\Framework\Constraint\IsEqual; use PHPUnit\Framework\Constraint\LogicalNot; +use PHPUnit\Framework\Constraint\RegularExpression; use PHPUnit\Framework\Constraint\StringContains; use PHPUnit\Framework\Constraint\TraversableContains; @@ -443,4 +444,24 @@ trait PolyfillAssertTrait static::assertFileExists($filename, $message); static::assertNotIsWritable($filename, $message); } + + /** + * Asserts that a string matches a given regular expression. + * + * @param string $pattern + * @param string $string + * @param string $message + * + * @return void + */ + public function assertMatchesRegularExpression($pattern, $string, $message = '') + { + static::assertThat( + $string, + new LogicalNot( + new RegularExpression($pattern) + ), + $message + ); + } } diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php index ffd3375e68..cb3fbf4490 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillTestCaseTrait.php @@ -11,10 +11,8 @@ namespace Symfony\Bridge\PhpUnit\Legacy; -use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use SebastianBergmann\RecursionContext\InvalidArgumentException; /** * This trait is @internal. @@ -118,18 +116,4 @@ trait PolyfillTestCaseTrait $property->setAccessible(true); $property->setValue($this, $messageRegExp); } - - /** - * Asserts that a string matches a given regular expression. - * - * @param string $pattern - * @param string $string - * @param string $message - * - * @return void - */ - public function assertMatchesRegularExpression($pattern, $string, $message = '') - { - $this->assertRegExp($pattern, $string, $message); - } } From d945b88c1ab083730547f3b15e3f70e4a5205541 Mon Sep 17 00:00:00 2001 From: Mohammad Emran Hasan Date: Mon, 13 Jul 2020 12:07:04 +0600 Subject: [PATCH 6/8] [PhpUnitBridge] Polyfill new phpunit 9.1 assertions --- src/Symfony/Bridge/PhpUnit/CHANGELOG.md | 2 +- .../PhpUnit/Legacy/PolyfillAssertTrait.php | 110 ++++++++++++++++-- 2 files changed, 102 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md index b85364ad7d..e9fc8f43c6 100644 --- a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md +++ b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md @@ -12,7 +12,7 @@ CHANGELOG ----- * added `ClassExistsMock` - * bumped PHP version from 5.3.3 to 5.5.9 + * bumped PHP version from 5.3.3 to 5.5.9 * split simple-phpunit bin into php file with code and a shell script 4.1.0 diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillAssertTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillAssertTrait.php index 646ea6b264..6b4941d542 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillAssertTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/PolyfillAssertTrait.php @@ -277,6 +277,17 @@ trait PolyfillAssertTrait static::assertFalse(is_readable($filename), $message ? $message : "Failed asserting that $filename is not readable."); } + /** + * @param string $filename + * @param string $message + * + * @return void + */ + public static function assertIsNotReadable($filename, $message = '') + { + static::assertNotIsReadable($filename, $message); + } + /** * @param string $filename * @param string $message @@ -301,6 +312,17 @@ trait PolyfillAssertTrait static::assertFalse(is_writable($filename), $message ? $message : "Failed asserting that $filename is not writable."); } + /** + * @param string $filename + * @param string $message + * + * @return void + */ + public static function assertIsNotWritable($filename, $message = '') + { + static::assertNotIsWritable($filename, $message); + } + /** * @param string $directory * @param string $message @@ -325,6 +347,17 @@ trait PolyfillAssertTrait static::assertFalse(is_dir($directory), $message ? $message : "Failed asserting that $directory does not exist."); } + /** + * @param string $directory + * @param string $message + * + * @return void + */ + public static function assertDirectoryDoesNotExist($directory, $message = '') + { + static::assertDirectoryNotExists($directory, $message); + } + /** * @param string $directory * @param string $message @@ -349,6 +382,17 @@ trait PolyfillAssertTrait static::assertNotIsReadable($directory, $message); } + /** + * @param string $directory + * @param string $message + * + * @return void + */ + public static function assertDirectoryIsNotReadable($directory, $message = '') + { + static::assertDirectoryNotIsReadable($directory, $message); + } + /** * @param string $directory * @param string $message @@ -373,6 +417,17 @@ trait PolyfillAssertTrait static::assertNotIsWritable($directory, $message); } + /** + * @param string $directory + * @param string $message + * + * @return void + */ + public static function assertDirectoryIsNotWritable($directory, $message = '') + { + static::assertDirectoryNotIsWritable($directory, $message); + } + /** * @param string $filename * @param string $message @@ -397,6 +452,17 @@ trait PolyfillAssertTrait static::assertFalse(file_exists($filename), $message ? $message : "Failed asserting that $filename does not exist."); } + /** + * @param string $filename + * @param string $message + * + * @return void + */ + public static function assertFileDoesNotExist($filename, $message = '') + { + static::assertFileNotExists($filename, $message); + } + /** * @param string $filename * @param string $message @@ -421,6 +487,17 @@ trait PolyfillAssertTrait static::assertNotIsReadable($filename, $message); } + /** + * @param string $filename + * @param string $message + * + * @return void + */ + public static function assertFileIsNotReadable($filename, $message = '') + { + static::assertFileNotIsReadable($filename, $message); + } + /** * @param string $filename * @param string $message @@ -446,22 +523,37 @@ trait PolyfillAssertTrait } /** - * Asserts that a string matches a given regular expression. + * @param string $filename + * @param string $message * + * @return void + */ + public static function assertFileIsNotWritable($filename, $message = '') + { + static::assertFileNotIsWritable($filename, $message); + } + + /** * @param string $pattern * @param string $string * @param string $message * * @return void */ - public function assertMatchesRegularExpression($pattern, $string, $message = '') + public static function assertMatchesRegularExpression($pattern, $string, $message = '') { - static::assertThat( - $string, - new LogicalNot( - new RegularExpression($pattern) - ), - $message - ); + static::assertRegExp($pattern, $string, $message); + } + + /** + * @param string $pattern + * @param string $string + * @param string $message + * + * @return void + */ + public static function assertDoesNotMatchRegularExpression($pattern, $string, $message = '') + { + static::assertNotRegExp($message, $string, $message); } } From 1b19f255a3455e2e574fde5642ef0dd101cc64ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sat, 23 Nov 2019 17:12:25 +0100 Subject: [PATCH 7/8] [PropertyInfo] Backport support for typed properties (PHP 7.4) --- .../Extractor/ReflectionExtractor.php | 28 +++++++++++++------ .../Extractor/ReflectionExtractorTest.php | 10 +++++++ .../Tests/Fixtures/Php74Dummy.php | 21 ++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php74Dummy.php diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index f30bc440e7..035a460e77 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -139,6 +139,18 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp */ public function getTypes($class, $property, array $context = []): ?array { + if (\PHP_VERSION_ID >= 70400) { + try { + $reflectionProperty = new \ReflectionProperty($class, $property); + $type = $reflectionProperty->getType(); + if (null !== $type) { + return $this->extractFromReflectionType($type, $reflectionProperty->getDeclaringClass()); + } + } catch (\ReflectionException $e) { + // noop + } + } + if ($fromMutator = $this->extractFromMutator($class, $property)) { return $fromMutator; } @@ -233,7 +245,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp if (!$reflectionType = $reflectionParameter->getType()) { return null; } - $type = $this->extractFromReflectionType($reflectionType, $reflectionMethod); + $type = $this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass()); if (1 === \count($type) && \in_array($prefix, $this->arrayMutatorPrefixes)) { $type = [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type[0])]; @@ -255,7 +267,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp } if ($reflectionType = $reflectionMethod->getReturnType()) { - return $this->extractFromReflectionType($reflectionType, $reflectionMethod); + return $this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass()); } if (\in_array($prefix, ['is', 'can', 'has'])) { @@ -290,7 +302,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp } $reflectionType = $parameter->getType(); - return $reflectionType ? $this->extractFromReflectionType($reflectionType, $constructor) : null; + return $reflectionType ? $this->extractFromReflectionType($reflectionType, $constructor->getDeclaringClass()) : null; } if ($parentClass = $reflectionClass->getParentClass()) { @@ -319,7 +331,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp return [new Type(static::MAP_TYPES[$type] ?? $type)]; } - private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionMethod $reflectionMethod): array + private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionClass $declaringClass): array { $types = []; $nullable = $reflectionType->allowsNull(); @@ -337,19 +349,19 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp } elseif ($type->isBuiltin()) { $types[] = new Type($phpTypeOrClass, $nullable); } else { - $types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod)); + $types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $declaringClass)); } } return $types; } - private function resolveTypeName(string $name, \ReflectionMethod $reflectionMethod): string + private function resolveTypeName(string $name, \ReflectionClass $declaringClass): string { if ('self' === $lcName = strtolower($name)) { - return $reflectionMethod->getDeclaringClass()->name; + return $declaringClass->name; } - if ('parent' === $lcName && $parent = $reflectionMethod->getDeclaringClass()->getParentClass()) { + if ('parent' === $lcName && $parent = $declaringClass->getParentClass()) { return $parent->name; } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 8a72e99e9b..e15574f619 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -19,6 +19,7 @@ use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\NotInstantiable; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyExtended2; +use Symfony\Component\PropertyInfo\Tests\Fixtures\Php74Dummy; use Symfony\Component\PropertyInfo\Type; /** @@ -389,4 +390,13 @@ class ReflectionExtractorTest extends TestCase [DefaultValue::class, 'foo', null], ]; } + + /** + * @requires PHP 7.4 + */ + public function testTypedProperties(): void + { + $this->assertEquals([new Type(Type::BUILTIN_TYPE_OBJECT, false, Dummy::class)], $this->extractor->getTypes(Php74Dummy::class, 'dummy')); + $this->assertEquals([new Type(Type::BUILTIN_TYPE_BOOL, true)], $this->extractor->getTypes(Php74Dummy::class, 'nullableBoolProp')); + } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php74Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php74Dummy.php new file mode 100644 index 0000000000..9d3146442d --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php74Dummy.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests\Fixtures; + +/** + * @author Kévin Dunglas + */ +class Php74Dummy +{ + public Dummy $dummy; + private ?bool $nullableBoolProp; +} From bf7654f245d7e0585c579379a426a40a919a42ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 28 Aug 2020 10:54:30 +0200 Subject: [PATCH 8/8] [PhpUnitBridge] Create a predictable symlink pointing to the local install --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index 4d3eeb8f14..e9cde5c2f9 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -283,6 +283,16 @@ EOPHP chdir($oldPwd); } +// Create a symlink with a predictable path pointing to the currently used version. +// This is useful for static analytics tools such as PHPStan having to load PHPUnit's classes +// and for other testing libraries such as Behat using PHPUnit's assertions. +chdir($PHPUNIT_DIR); +if (file_exists('phpunit')) { + @unlink('phpunit'); +} +@symlink($PHPUNIT_VERSION_DIR, 'phpunit'); +chdir($oldPwd); + if ($PHPUNIT_VERSION < 8.0) { $argv = array_filter($argv, function ($v) use (&$argc) { if ('--do-not-cache-result' !== $v) {