From 29586b464b5c39ec3c0a99134db89b7e90f6a346 Mon Sep 17 00:00:00 2001 From: karser Date: Fri, 1 Feb 2019 13:44:52 +0200 Subject: [PATCH 1/2] Added ConstructorExtractor which has higher priority than PhpDocExtractor and ReflectionExtractor --- .../FrameworkExtension.php | 1 + .../FrameworkBundle/FrameworkBundle.php | 2 + .../Resources/config/property_info.xml | 6 ++ .../Tests/Functional/PropertyInfoTest.php | 24 ++++++ .../PropertyInfoConstructorPass.php | 50 ++++++++++++ ...structorArgumentTypeExtractorInterface.php | 30 ++++++++ .../Extractor/ConstructorExtractor.php | 48 ++++++++++++ .../Extractor/PhpDocExtractor.php | 73 +++++++++++++++++- .../Extractor/ReflectionExtractor.php | 76 ++++++++++++++++--- .../PropertyInfoConstructorPassTest.php | 54 +++++++++++++ .../Extractor/ConstructorExtractorTest.php | 40 ++++++++++ .../Tests/Extractor/PhpDocExtractorTest.php | 19 +++++ .../Extractor/ReflectionExtractorTest.php | 19 +++++ .../Tests/Fixtures/ConstructorDummy.php | 30 ++++++++ .../Tests/Fixtures/DummyExtractor.php | 11 ++- 15 files changed, 472 insertions(+), 11 deletions(-) create mode 100644 src/Symfony/Component/PropertyInfo/DependencyInjection/PropertyInfoConstructorPass.php create mode 100644 src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php create mode 100644 src/Symfony/Component/PropertyInfo/Extractor/ConstructorExtractor.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/DependencyInjection/PropertyInfoConstructorPassTest.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Extractor/ConstructorExtractorTest.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/ConstructorDummy.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index a46e552a255e3..c32b347b5be82 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1583,6 +1583,7 @@ private function registerPropertyInfoConfiguration(ContainerBuilder $container, $definition->setPrivate(true); $definition->addTag('property_info.description_extractor', ['priority' => -1000]); $definition->addTag('property_info.type_extractor', ['priority' => -1001]); + $definition->addTag('property_info.constructor_extractor', ['priority' => -1001]); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index daf7a37bf8547..17b4645774905 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -42,6 +42,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass; use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass; use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoConstructorPass; use Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass; use Symfony\Component\Routing\DependencyInjection\RoutingResolverPass; use Symfony\Component\Serializer\DependencyInjection\SerializerPass; @@ -116,6 +117,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new FragmentRendererPass()); $this->addCompilerPassIfExists($container, SerializerPass::class); $this->addCompilerPassIfExists($container, PropertyInfoPass::class); + $this->addCompilerPassIfExists($container, PropertyInfoConstructorPass::class); $container->addCompilerPass(new DataCollectorTranslatorPass()); $container->addCompilerPass(new ControllerArgumentValueResolverPass()); $container->addCompilerPass(new CachePoolPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 32); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml index a893127276564..6dbe61ee2223a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml @@ -19,7 +19,13 @@ + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php index 832b45b818f76..6b74f9771024f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\PropertyInfo\Type; class PropertyInfoTest extends WebTestCase @@ -22,6 +23,29 @@ public function testPhpDocPriority() $this->assertEquals([new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_INT))], $container->get('test.property_info')->getTypes('Symfony\Bundle\FrameworkBundle\Tests\Functional\Dummy', 'codes')); } + + /** + * @dataProvider constructorOverridesPropertyTypeProvider + */ + public function testConstructorOverridesPropertyType(ContainerInterface $container, $property, array $type = null) + { + $extractor = $container->get('test.property_info'); + $this->assertEquals($type, $extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy', $property)); + } + + public function constructorOverridesPropertyTypeProvider() + { + static::bootKernel(['test_case' => 'Serializer']); + $c = static::$kernel->getContainer(); + + return [ + [$c, 'timezone', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeZone')]], + [$c, 'date', [new Type(Type::BUILTIN_TYPE_INT)]], + [$c, 'dateObject', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeInterface')]], + [$c, 'dateTime', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')]], + [$c, 'ddd', null], + ]; + } } class Dummy diff --git a/src/Symfony/Component/PropertyInfo/DependencyInjection/PropertyInfoConstructorPass.php b/src/Symfony/Component/PropertyInfo/DependencyInjection/PropertyInfoConstructorPass.php new file mode 100644 index 0000000000000..ccf84e82faa3c --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/DependencyInjection/PropertyInfoConstructorPass.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\DependencyInjection; + +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * Adds extractors to the property_info.constructor_extractor service. + * + * @author Dmitrii Poddubnyi + */ +class PropertyInfoConstructorPass implements CompilerPassInterface +{ + use PriorityTaggedServiceTrait; + + private $service; + private $tag; + + public function __construct($service = 'property_info.constructor_extractor', $tag = 'property_info.constructor_extractor') + { + $this->service = $service; + $this->tag = $tag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->service)) { + return; + } + $definition = $container->getDefinition($this->service); + + $listExtractors = $this->findAndSortTaggedServices($this->tag, $container); + $definition->replaceArgument(0, new IteratorArgument($listExtractors)); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php b/src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php new file mode 100644 index 0000000000000..b75526cb2f8fe --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Extractor; + +/** + * Infers the constructor argument type. + * + * @author Dmitrii Poddubnyi + */ +interface ConstructorArgumentTypeExtractorInterface +{ + /** + * Gets types of an argument from constructor. + * + * @param string $class + * @param string $property + * + * @return Type[]|null + */ + public function getTypesFromConstructor($class, $property); +} diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ConstructorExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ConstructorExtractor.php new file mode 100644 index 0000000000000..9695523bc050a --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Extractor/ConstructorExtractor.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Extractor; + +use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; + +/** + * Extracts the constructor argument type using ConstructorArgumentTypeExtractorInterface implementations. + * + * @author Dmitrii Poddubnyi + */ +class ConstructorExtractor implements PropertyTypeExtractorInterface +{ + /** @var iterable|ConstructorArgumentTypeExtractorInterface[] */ + private $extractors; + + /** + * @param iterable|ConstructorArgumentTypeExtractorInterface[] $extractors + */ + public function __construct($extractors = []) + { + $this->extractors = $extractors; + } + + /** + * {@inheritdoc} + */ + public function getTypes($class, $property, array $context = []) + { + foreach ($this->extractors as $extractor) { + $value = $extractor->getTypesFromConstructor($class, $property); + if (null !== $value) { + return $value; + } + } + + return null; + } +} diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index 7d47cd047003f..6e94fa4dc3f2d 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -27,7 +27,7 @@ * * @final since version 3.3 */ -class PhpDocExtractor implements PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface +class PhpDocExtractor implements PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, ConstructorArgumentTypeExtractorInterface { const PROPERTY = 0; const ACCESSOR = 1; @@ -151,6 +151,32 @@ public function getTypes($class, $property, array $context = []) return [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $types[0])]; } + /** + * {@inheritdoc} + */ + public function getTypesFromConstructor($class, $property) + { + $docBlock = $this->getDocBlockFromConstructor($class, $property); + + if (!$docBlock) { + return; + } + + $types = []; + /** @var DocBlock\Tags\Var_|DocBlock\Tags\Return_|DocBlock\Tags\Param $tag */ + foreach ($docBlock->getTagsByName('param') as $tag) { + if ($tag && null !== $tag->getType()) { + $types = array_merge($types, $this->phpDocTypeHelper->getTypes($tag->getType())); + } + } + + if (!isset($types[0])) { + return; + } + + return $types; + } + /** * Gets the DocBlock for this property. * @@ -189,6 +215,51 @@ private function getDocBlock($class, $property) return $this->docBlocks[$propertyHash] = $data; } + /** + * Gets the DocBlock from a constructor. + * + * @param string $class + * @param string $property + * + * @return DocBlock|null + */ + private function getDocBlockFromConstructor($class, $property) + { + try { + $reflectionClass = new \ReflectionClass($class); + } catch (\ReflectionException $e) { + return null; + } + $reflectionConstructor = $reflectionClass->getConstructor(); + if (!$reflectionConstructor) { + return null; + } + + try { + $docBlock = $this->docBlockFactory->create($reflectionConstructor, $this->contextFactory->createFromReflector($reflectionConstructor)); + + return $this->filterDocBlockParams($docBlock, $property); + } catch (\InvalidArgumentException $e) { + return null; + } + } + + /** + * @param DocBlock $docBlock + * @param string $allowedParam + * + * @return DocBlock + */ + private function filterDocBlockParams(DocBlock $docBlock, $allowedParam) + { + $tags = array_values(array_filter($docBlock->getTagsByName('param'), function ($tag) use ($allowedParam) { + return $tag instanceof DocBlock\Tags\Param && $allowedParam === $tag->getVariableName(); + })); + + return new DocBlock($docBlock->getSummary(), $docBlock->getDescription(), $tags, $docBlock->getContext(), + $docBlock->getLocation(), $docBlock->isTemplateStart(), $docBlock->isTemplateEnd()); + } + /** * Gets the DocBlock from a property. * diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 513549219f21e..7dc6bcc7fb92d 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -24,7 +24,7 @@ * * @final since version 3.3 */ -class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface +class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface, ConstructorArgumentTypeExtractorInterface { /** * @internal @@ -126,6 +126,47 @@ public function getTypes($class, $property, array $context = []) } } + /** + * {@inheritdoc} + */ + public function getTypesFromConstructor($class, $property) + { + try { + $reflection = new \ReflectionClass($class); + } catch (\ReflectionException $e) { + return null; + } + if (!$reflectionConstructor = $reflection->getConstructor()) { + return null; + } + if (!$reflectionParameter = $this->getReflectionParameterFromConstructor($property, $reflectionConstructor)) { + return null; + } + if (!$type = $this->extractFromReflectionMethod($reflectionParameter, $reflectionConstructor)) { + return null; + } + + return [$type]; + } + + /** + * @param string $property + * @param \ReflectionMethod $reflectionConstructor + * + * @return \ReflectionParameter|null + */ + private function getReflectionParameterFromConstructor($property, \ReflectionMethod $reflectionConstructor) + { + $reflectionParameter = null; + foreach ($reflectionConstructor->getParameters() as $reflectionParameter) { + if ($reflectionParameter->getName() === $property) { + return $reflectionParameter; + } + } + + return null; + } + /** * {@inheritdoc} */ @@ -172,16 +213,37 @@ private function extractFromMutator($class, $property) $reflectionParameters = $reflectionMethod->getParameters(); $reflectionParameter = $reflectionParameters[0]; + if (!$type = $this->extractFromReflectionMethod($reflectionParameter, $reflectionMethod)) { + return null; + } + + if (\in_array($prefix, $this->arrayMutatorPrefixes)) { + $type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type); + } + + return [$type]; + } + + /** + * @param \ReflectionParameter $reflectionParameter + * @param \ReflectionMethod $reflectionMethod + * + * @return Type|null + */ + private function extractFromReflectionMethod(\ReflectionParameter $reflectionParameter, \ReflectionMethod $reflectionMethod) + { if ($this->supportsParameterType) { if (!$reflectionType = $reflectionParameter->getType()) { - return; + return null; } $type = $this->extractFromReflectionType($reflectionType, $reflectionMethod); // HHVM reports variadics with "array" but not builtin type hints if (!$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type->getBuiltinType()) { - return; + return null; } + + return $type; } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $reflectionParameter, $info)) { if (Type::BUILTIN_TYPE_ARRAY === $info[1]) { $type = new Type(Type::BUILTIN_TYPE_ARRAY, $reflectionParameter->allowsNull(), null, true); @@ -190,15 +252,11 @@ private function extractFromMutator($class, $property) } else { $type = new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $this->resolveTypeName($info[1], $reflectionMethod)); } - } else { - return; - } - if (\in_array($prefix, $this->arrayMutatorPrefixes)) { - $type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type); + return $type; } - return [$type]; + return null; } /** diff --git a/src/Symfony/Component/PropertyInfo/Tests/DependencyInjection/PropertyInfoConstructorPassTest.php b/src/Symfony/Component/PropertyInfo/Tests/DependencyInjection/PropertyInfoConstructorPassTest.php new file mode 100644 index 0000000000000..ee3151f2710a9 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/DependencyInjection/PropertyInfoConstructorPassTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoConstructorPass; + +class PropertyInfoConstructorPassTest extends TestCase +{ + public function testServicesAreOrderedAccordingToPriority() + { + $container = new ContainerBuilder(); + + $tag = 'property_info.constructor_extractor'; + $definition = $container->register('property_info.constructor_extractor')->setArguments([null, null]); + $container->register('n2')->addTag($tag, ['priority' => 100]); + $container->register('n1')->addTag($tag, ['priority' => 200]); + $container->register('n3')->addTag($tag); + + $pass = new PropertyInfoConstructorPass(); + $pass->process($container); + + $expected = new IteratorArgument([ + new Reference('n1'), + new Reference('n2'), + new Reference('n3'), + ]); + $this->assertEquals($expected, $definition->getArgument(0)); + } + + public function testReturningEmptyArrayWhenNoService() + { + $container = new ContainerBuilder(); + $propertyInfoExtractorDefinition = $container->register('property_info.constructor_extractor') + ->setArguments([[]]); + + $pass = new PropertyInfoConstructorPass(); + $pass->process($container); + + $this->assertEquals(new IteratorArgument([]), $propertyInfoExtractorDefinition->getArgument(0)); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ConstructorExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ConstructorExtractorTest.php new file mode 100644 index 0000000000000..11a28c0f7c824 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ConstructorExtractorTest.php @@ -0,0 +1,40 @@ + + */ +class ConstructorExtractorTest extends TestCase +{ + /** + * @var ConstructorExtractor + */ + private $extractor; + + protected function setUp() + { + $this->extractor = new ConstructorExtractor([new DummyExtractor()]); + } + + public function testInstanceOf() + { + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface', $this->extractor); + } + + public function testGetTypes() + { + $this->assertEquals([new Type(Type::BUILTIN_TYPE_STRING)], $this->extractor->getTypes('Foo', 'bar', [])); + } + + public function testGetTypes_ifNoExtractors() + { + $extractor = new ConstructorExtractor([]); + $this->assertNull($extractor->getTypes('Foo', 'bar', [])); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php index f4f9e9dc77e29..0d093b0b6be51 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php @@ -213,6 +213,25 @@ public function testDocBlockFallback($property, $types) { $this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DockBlockFallback', $property)); } + + /** + * @dataProvider constructorTypesProvider + */ + public function testExtractConstructorTypes($property, array $type = null) + { + $this->assertEquals($type, $this->extractor->getTypesFromConstructor('Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy', $property)); + } + + public function constructorTypesProvider() + { + return [ + ['date', [new Type(Type::BUILTIN_TYPE_INT)]], + ['timezone', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeZone')]], + ['dateObject', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeInterface')]], + ['dateTime', null], + ['ddd', null], + ]; + } } class EmptyDocBlock diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 0ed5390bb5882..68bca2dbbcbaa 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -263,4 +263,23 @@ public function testSingularize() $this->assertTrue($this->extractor->isWritable(AdderRemoverDummy::class, 'feet')); $this->assertEquals(['analyses', 'feet'], $this->extractor->getProperties(AdderRemoverDummy::class)); } + + /** + * @dataProvider constructorTypesProvider + */ + public function testExtractConstructorTypes($property, array $type = null) + { + $this->assertEquals($type, $this->extractor->getTypesFromConstructor('Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy', $property)); + } + + public function constructorTypesProvider() + { + return [ + ['timezone', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeZone')]], + ['date', null], + ['dateObject', null], + ['dateTime', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')]], + ['ddd', null], + ]; + } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ConstructorDummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ConstructorDummy.php new file mode 100644 index 0000000000000..23ef5cceaef75 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ConstructorDummy.php @@ -0,0 +1,30 @@ + + */ +class ConstructorDummy +{ + /** @var string */ + private $timezone; + + /** @var \DateTimeInterface */ + private $date; + + /** @var int */ + private $dateTime; + + /** + * @param \DateTimeZone $timezone + * @param int $date Timestamp + * @param \DateTimeInterface $dateObject + */ + public function __construct(\DateTimeZone $timezone, $date, $dateObject, \DateTime $dateTime) + { + $this->timezone = $timezone->getName(); + $this->date = \DateTime::createFromFormat('U', $date); + $this->dateTime = $dateTime->getTimestamp(); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php index cb17020a55eb4..88eda16311e31 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php @@ -11,6 +11,7 @@ namespace Symfony\Component\PropertyInfo\Tests\Fixtures; +use Symfony\Component\PropertyInfo\Extractor\ConstructorArgumentTypeExtractorInterface; use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface; use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; @@ -20,7 +21,7 @@ /** * @author Kévin Dunglas */ -class DummyExtractor implements PropertyListExtractorInterface, PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface +class DummyExtractor implements PropertyListExtractorInterface, PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface, ConstructorArgumentTypeExtractorInterface { /** * {@inheritdoc} @@ -46,6 +47,14 @@ public function getTypes($class, $property, array $context = []) return [new Type(Type::BUILTIN_TYPE_INT)]; } + /** + * {@inheritdoc} + */ + public function getTypesFromConstructor($class, $property) + { + return [new Type(Type::BUILTIN_TYPE_STRING)]; + } + /** * {@inheritdoc} */ From 6eade3b8dacd4b5184f0ac880ca8dfee6162badb Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 6 Feb 2019 16:09:37 +0100 Subject: [PATCH 2/2] fix supported PropertyInfo component version constraints --- src/Symfony/Bundle/FrameworkBundle/composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index c8ed98787e15e..a337d66628b29 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -52,7 +52,7 @@ "symfony/var-dumper": "~3.3|~4.0", "symfony/workflow": "~3.3|~4.0", "symfony/yaml": "~3.2|~4.0", - "symfony/property-info": "~3.3|~4.0", + "symfony/property-info": "~3.4.23|^4.2.4", "symfony/lock": "~3.4|~4.0", "symfony/web-link": "~3.3|~4.0", "doctrine/annotations": "~1.0", @@ -66,7 +66,7 @@ "symfony/asset": "<3.3", "symfony/console": "<3.4", "symfony/form": "<3.4", - "symfony/property-info": "<3.3", + "symfony/property-info": "<3.4.23|>=4.0.0,<4.2.4", "symfony/serializer": "<3.3", "symfony/stopwatch": "<3.4", "symfony/translation": "<3.4",