diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 87ce95e44bc13..cad267ccd8eae 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -1413,6 +1413,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 999f4aed36f96..1306a9bb7ef54 100644
--- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -44,6 +44,7 @@
use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Messenger\DependencyInjection\MessengerPass;
+use Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoConstructorPass;
use Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass;
use Symfony\Component\Routing\DependencyInjection\RoutingResolverPass;
use Symfony\Component\Serializer\DependencyInjection\SerializerPass;
@@ -107,6 +108,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 e8778f70822bf..925cc62f3bea1 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml
@@ -25,8 +25,14 @@
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php
index 61669e90adbc7..b654008dacb2b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php
@@ -21,6 +21,27 @@ 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))], static::$container->get('property_info')->getTypes('Symfony\Bundle\FrameworkBundle\Tests\Functional\Dummy', 'codes'));
}
+
+ /**
+ * @dataProvider constructorOverridesPropertyTypeProvider
+ */
+ public function testConstructorOverridesPropertyType($property, array $type = null)
+ {
+ static::bootKernel(['test_case' => 'Serializer']);
+ $extractor = static::$container->get('property_info');
+ $this->assertEquals($type, $extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummy', $property));
+ }
+
+ public function constructorOverridesPropertyTypeProvider()
+ {
+ return [
+ ['timezone', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeZone')]],
+ ['date', [new Type(Type::BUILTIN_TYPE_INT)]],
+ ['dateObject', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTimeInterface')]],
+ ['dateTime', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')]],
+ ['ddd', null],
+ ];
+ }
}
class Dummy
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index e18554972e423..cf129bc336e0d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -54,7 +54,7 @@
"symfony/var-dumper": "~3.4|~4.0",
"symfony/workflow": "^4.1",
"symfony/yaml": "~3.4|~4.0",
- "symfony/property-info": "~3.4|~4.0",
+ "symfony/property-info": "~3.4.23|^4.2.4",
"symfony/lock": "~3.4|~4.0",
"symfony/web-link": "~3.4|~4.0",
"doctrine/annotations": "~1.0",
@@ -70,7 +70,7 @@
"symfony/dotenv": "<4.2",
"symfony/form": "<4.2",
"symfony/messenger": "<4.2",
- "symfony/property-info": "<3.4",
+ "symfony/property-info": "<3.4.23|>=4.0.0,<4.2.4",
"symfony/serializer": "<4.2",
"symfony/stopwatch": "<3.4",
"symfony/translation": "<4.2",
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..3192b79fb0646
--- /dev/null
+++ b/src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php
@@ -0,0 +1,32 @@
+
+ *
+ * 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\Type;
+
+/**
+ * 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 4837d2200c852..1e0a401c4034b 100644
--- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php
+++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php
@@ -27,7 +27,7 @@
*
* @final
*/
-class PhpDocExtractor implements PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface
+class PhpDocExtractor implements PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, ConstructorArgumentTypeExtractorInterface
{
const PROPERTY = 0;
const ACCESSOR = 1;
@@ -151,6 +151,77 @@ 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 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());
+ }
+
private function getDocBlock(string $class, string $property): array
{
$propertyHash = sprintf('%s::%s', $class, $property);
diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
index 0ed1e4e2afe3d..1543674184b5a 100644
--- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
+++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
@@ -25,7 +25,7 @@
*
* @final
*/
-class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface, PropertyInitializableExtractorInterface
+class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface, PropertyInitializableExtractorInterface, ConstructorArgumentTypeExtractorInterface
{
/**
* @internal
@@ -119,6 +119,50 @@ 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 (!$reflectionType = $reflectionParameter->getType()) {
+ return null;
+ }
+ if (!$type = $this->extractFromReflectionType($reflectionType, $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}
*/
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 930dc6e24c9b8..33280e79032dd 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php
@@ -247,6 +247,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 e58c70d41d702..cb5e02ceb0d5b 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
@@ -293,4 +293,23 @@ public function getInitializableProperties(): array
[NotInstantiable::class, 'foo', false],
];
}
+
+ /**
+ * @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 9003b2fa38a6d..d75f1bc0d388f 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\PropertyInitializableExtractorInterface;
@@ -21,7 +22,7 @@
/**
* @author Kévin Dunglas
*/
-class DummyExtractor implements PropertyListExtractorInterface, PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface, PropertyInitializableExtractorInterface
+class DummyExtractor implements PropertyListExtractorInterface, PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface, PropertyInitializableExtractorInterface, ConstructorArgumentTypeExtractorInterface
{
/**
* {@inheritdoc}
@@ -47,6 +48,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}
*/