diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index e90579efbb570..f9fb721fb8298 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -53,11 +53,35 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property */ private $phpDocTypeHelper; - public function __construct(DocBlockFactoryInterface $docBlockFactory = null) + /** + * @var string[] + */ + private $mutatorPrefixes; + + /** + * @var string[] + */ + private $accessorPrefixes; + + /** + * @var string[] + */ + private $arrayMutatorPrefixes; + + /** + * @param DocBlockFactoryInterface $docBlockFactory + * @param string[]|null $mutatorPrefixes + * @param string[]|null $accessorPrefixes + * @param string[]|null $arrayMutatorPrefixes + */ + public function __construct(DocBlockFactoryInterface $docBlockFactory = null, array $mutatorPrefixes = null, array $accessorPrefixes = null, array $arrayMutatorPrefixes = null) { $this->docBlockFactory = $docBlockFactory ?: DocBlockFactory::createInstance(); $this->contextFactory = new ContextFactory(); $this->phpDocTypeHelper = new PhpDocTypeHelper(); + $this->mutatorPrefixes = null !== $mutatorPrefixes ? $mutatorPrefixes : ReflectionExtractor::$defaultMutatorPrefixes; + $this->accessorPrefixes = null !== $accessorPrefixes ? $accessorPrefixes : ReflectionExtractor::$defaultAccessorPrefixes; + $this->arrayMutatorPrefixes = null !== $arrayMutatorPrefixes ? $arrayMutatorPrefixes : ReflectionExtractor::$defaultArrayMutatorPrefixes; } /** @@ -137,7 +161,7 @@ public function getTypes($class, $property, array $context = array()) return; } - if (!in_array($prefix, ReflectionExtractor::$arrayMutatorPrefixes)) { + if (!in_array($prefix, $this->arrayMutatorPrefixes)) { return $types; } @@ -217,7 +241,7 @@ private function getDocBlockFromProperty($class, $property) */ private function getDocBlockFromMethod($class, $ucFirstProperty, $type) { - $prefixes = $type === self::ACCESSOR ? ReflectionExtractor::$accessorPrefixes : ReflectionExtractor::$mutatorPrefixes; + $prefixes = $type === self::ACCESSOR ? $this->accessorPrefixes : $this->mutatorPrefixes; $prefix = null; foreach ($prefixes as $prefix) { diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 228aa583e8feb..772f975a89114 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -31,27 +31,53 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp * * @var string[] */ - public static $mutatorPrefixes = array('add', 'remove', 'set'); + public static $defaultMutatorPrefixes = array('add', 'remove', 'set'); /** * @internal * * @var string[] */ - public static $accessorPrefixes = array('is', 'can', 'get'); + public static $defaultAccessorPrefixes = array('is', 'can', 'get'); /** * @internal * * @var string[] */ - public static $arrayMutatorPrefixes = array('add', 'remove'); + public static $defaultArrayMutatorPrefixes = array('add', 'remove'); + /** + * @var bool + */ private $supportsParameterType; - public function __construct() + /** + * @var string[] + */ + private $mutatorPrefixes; + + /** + * @var string[] + */ + private $accessorPrefixes; + + /** + * @var string[] + */ + private $arrayMutatorPrefixes; + + /** + * @param string[]|null $mutatorPrefixes + * @param string[]|null $accessorPrefixes + * @param string[]|null $arrayMutatorPrefixes + */ + public function __construct(array $mutatorPrefixes = null, array $accessorPrefixes = null, array $arrayMutatorPrefixes = null) { $this->supportsParameterType = method_exists('ReflectionParameter', 'getType'); + $this->mutatorPrefixes = null !== $mutatorPrefixes ? $mutatorPrefixes : self::$defaultMutatorPrefixes; + $this->accessorPrefixes = null !== $accessorPrefixes ? $accessorPrefixes : self::$defaultAccessorPrefixes; + $this->arrayMutatorPrefixes = null !== $arrayMutatorPrefixes ? $arrayMutatorPrefixes : self::$defaultArrayMutatorPrefixes; } /** @@ -174,7 +200,7 @@ private function extractFromMutator($class, $property) return; } - if (in_array($prefix, self::$arrayMutatorPrefixes)) { + if (in_array($prefix, $this->arrayMutatorPrefixes)) { $type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type); } @@ -266,7 +292,7 @@ private function getAccessorMethod($class, $property) { $ucProperty = ucfirst($property); - foreach (self::$accessorPrefixes as $prefix) { + foreach ($this->accessorPrefixes as $prefix) { try { $reflectionMethod = new \ReflectionMethod($class, $prefix.$ucProperty); if ($reflectionMethod->isStatic()) { @@ -298,9 +324,9 @@ private function getMutatorMethod($class, $property) $ucProperty = ucfirst($property); $ucSingulars = (array) Inflector::singularize($ucProperty); - foreach (self::$mutatorPrefixes as $prefix) { + foreach ($this->mutatorPrefixes as $prefix) { $names = array($ucProperty); - if (in_array($prefix, self::$arrayMutatorPrefixes)) { + if (in_array($prefix, $this->arrayMutatorPrefixes)) { $names = array_merge($names, $ucSingulars); } @@ -332,10 +358,10 @@ private function getMutatorMethod($class, $property) */ private function getPropertyName($methodName, array $reflectionProperties) { - $pattern = implode('|', array_merge(self::$accessorPrefixes, self::$mutatorPrefixes)); + $pattern = implode('|', array_merge($this->accessorPrefixes, $this->mutatorPrefixes)); - if (preg_match('/^('.$pattern.')(.+)$/i', $methodName, $matches)) { - if (!in_array($matches[1], self::$arrayMutatorPrefixes)) { + if ('' !== $pattern && preg_match('/^('.$pattern.')(.+)$/i', $methodName, $matches)) { + if (!in_array($matches[1], $this->arrayMutatorPrefixes)) { return $matches[2]; } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php index d0eb3eed06c49..8d1d9ab0ca160 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php @@ -40,6 +40,26 @@ public function testExtract($property, array $type = null, $shortDescription, $l $this->assertSame($longDescription, $this->extractor->getLongDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); } + /** + * @dataProvider typesWithCustomPrefixesProvider + */ + public function testExtractTypesWithCustomPrefixes($property, array $type = null) + { + $customExtractor = new PhpDocExtractor(null, array('add', 'remove'), array('is', 'can')); + + $this->assertEquals($type, $customExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); + } + + /** + * @dataProvider typesWithNoPrefixesProvider + */ + public function testExtractTypesWithNoPrefixes($property, array $type = null) + { + $noPrefixExtractor = new PhpDocExtractor(null, array(), array(), array()); + + $this->assertEquals($type, $noPrefixExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); + } + public function typesProvider() { return array( @@ -75,6 +95,76 @@ public function typesProvider() ); } + public function typesWithCustomPrefixesProvider() + { + return array( + array('foo', null, 'Short description.', 'Long description.'), + array('bar', array(new Type(Type::BUILTIN_TYPE_STRING)), 'This is bar', null), + array('baz', array(new Type(Type::BUILTIN_TYPE_INT)), 'Should be used.', null), + array('foo2', array(new Type(Type::BUILTIN_TYPE_FLOAT)), null, null), + array('foo3', array(new Type(Type::BUILTIN_TYPE_CALLABLE)), null, null), + array('foo4', array(new Type(Type::BUILTIN_TYPE_NULL)), null, null), + array('foo5', null, null, null), + array( + 'files', + array( + new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')), + new Type(Type::BUILTIN_TYPE_RESOURCE), + ), + null, + null, + ), + array('bal', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')), null, null), + array('parent', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')), null, null), + array('collection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null), + array('a', null, 'A.', null), + array('b', null, 'B.', null), + array('c', array(new Type(Type::BUILTIN_TYPE_BOOL, true)), null, null), + array('d', array(new Type(Type::BUILTIN_TYPE_BOOL)), null, null), + array('e', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_RESOURCE))), null, null), + array('f', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null), + array('g', array(new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)), 'Nullable array.', null), + array('donotexist', null, null, null), + array('staticGetter', null, null, null), + array('staticSetter', null, null, null), + ); + } + + public function typesWithNoPrefixesProvider() + { + return array( + array('foo', null, 'Short description.', 'Long description.'), + array('bar', array(new Type(Type::BUILTIN_TYPE_STRING)), 'This is bar', null), + array('baz', array(new Type(Type::BUILTIN_TYPE_INT)), 'Should be used.', null), + array('foo2', array(new Type(Type::BUILTIN_TYPE_FLOAT)), null, null), + array('foo3', array(new Type(Type::BUILTIN_TYPE_CALLABLE)), null, null), + array('foo4', array(new Type(Type::BUILTIN_TYPE_NULL)), null, null), + array('foo5', null, null, null), + array( + 'files', + array( + new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'SplFileInfo')), + new Type(Type::BUILTIN_TYPE_RESOURCE), + ), + null, + null, + ), + array('bal', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')), null, null), + array('parent', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')), null, null), + array('collection', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null), + array('a', null, 'A.', null), + array('b', null, 'B.', null), + array('c', null, null, null), + array('d', null, null, null), + array('e', null, null, null), + array('f', null, null, null), + array('g', array(new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)), 'Nullable array.', null), + array('donotexist', null, null, null), + array('staticGetter', null, null, null), + array('staticSetter', null, null, null), + ); + } + public function testReturnNullOnEmptyDocBlock() { $this->assertNull($this->extractor->getShortDescription(EmptyDocBlock::class, 'foo')); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php index 573528c012f55..5bf5d2e69ab8e 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php @@ -60,6 +60,56 @@ public function testGetProperties() ); } + public function testGetPropertiesWithCustomPrefixes() + { + $customExtractor = new ReflectionExtractor(array('add', 'remove'), array('is', 'can')); + + $this->assertSame( + array( + 'bal', + 'parent', + 'collection', + 'B', + 'Guid', + 'g', + 'foo', + 'foo2', + 'foo3', + 'foo4', + 'foo5', + 'files', + 'c', + 'd', + 'e', + 'f', + ), + $customExtractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy') + ); + } + + public function testGetPropertiesWithNoPrefixes() + { + $noPrefixExtractor = new ReflectionExtractor(array(), array(), array()); + + $this->assertSame( + array( + 'bal', + 'parent', + 'collection', + 'B', + 'Guid', + 'g', + 'foo', + 'foo2', + 'foo3', + 'foo4', + 'foo5', + 'files', + ), + $noPrefixExtractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy') + ); + } + /** * @dataProvider typesProvider */