From 4cbb60c38230af0f875a02b9ab1195a5be737b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 28 Mar 2016 11:03:47 +0200 Subject: [PATCH] [PropertyInfo] Support singular adder and remover --- .../Extractor/ReflectionExtractor.php | 50 ++++++++++++++----- .../Extractors/ReflectionExtractorTest.php | 8 +++ .../Tests/Fixtures/AdderRemoverDummy.php | 29 +++++++++++ .../Component/PropertyInfo/composer.json | 3 +- 4 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/AdderRemoverDummy.php diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 8226655f7a..0a43d018ee 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -11,6 +11,7 @@ namespace Symfony\Component\PropertyInfo\Extractor; +use Symfony\Component\Inflector\Inflector; use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; @@ -55,13 +56,17 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp return; } + $reflectionProperties = $reflectionClass->getProperties(); + $properties = array(); - foreach ($reflectionClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflectionProperty) { - $properties[$reflectionProperty->name] = true; + foreach ($reflectionProperties as $reflectionProperty) { + if ($reflectionProperty->isPublic()) { + $properties[$reflectionProperty->name] = true; + } } foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { - $propertyName = $this->getPropertyName($reflectionMethod->name); + $propertyName = $this->getPropertyName($reflectionMethod->name, $reflectionProperties); if (!$propertyName || isset($properties[$propertyName])) { continue; } @@ -312,17 +317,25 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp private function getMutatorMethod($class, $property) { $ucProperty = ucfirst($property); + $ucSingulars = (array) Inflector::singularize($ucProperty); foreach (self::$mutatorPrefixes as $prefix) { - try { - $reflectionMethod = new \ReflectionMethod($class, $prefix.$ucProperty); + $names = array($ucProperty); + if (in_array($prefix, self::$arrayMutatorPrefixes)) { + $names = array_merge($names, $ucSingulars); + } - // Parameter can be optional to allow things like: method(array $foo = null) - if ($reflectionMethod->getNumberOfParameters() >= 1) { - return array($reflectionMethod, $prefix); + foreach ($names as $name) { + try { + $reflectionMethod = new \ReflectionMethod($class, $prefix.$name); + + // Parameter can be optional to allow things like: method(array $foo = null) + if ($reflectionMethod->getNumberOfParameters() >= 1) { + return array($reflectionMethod, $prefix); + } + } catch (\ReflectionException $reflectionException) { + // Try the next one if method does not exist } - } catch (\ReflectionException $reflectionException) { - // Try the next prefix if the method doesn't exist } } } @@ -330,15 +343,28 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp /** * Extracts a property name from a method name. * - * @param string $methodName + * @param string $methodName + * @param \ReflectionProperty[] $reflectionProperties * * @return string */ - private function getPropertyName($methodName) + private function getPropertyName($methodName, array $reflectionProperties) { $pattern = implode('|', array_merge(self::$accessorPrefixes, self::$mutatorPrefixes)); if (preg_match('/^('.$pattern.')(.+)$/i', $methodName, $matches)) { + if (!in_array($matches[1], self::$arrayMutatorPrefixes)) { + return $matches[2]; + } + + foreach ($reflectionProperties as $reflectionProperty) { + foreach ((array) Inflector::singularize($reflectionProperty->name) as $name) { + if (strtolower($name) === strtolower($matches[2])) { + return $reflectionProperty->name; + } + } + } + return $matches[2]; } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php index dfc13c025e..dff4e731b4 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\PropertyInfo\Tests\Extractor; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; +use Symfony\Component\PropertyInfo\Tests\Fixtures\AdderRemoverDummy; use Symfony\Component\PropertyInfo\Type; /** @@ -119,4 +120,11 @@ class ReflectionExtractorTest extends \PHPUnit_Framework_TestCase $this->assertTrue($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'e', array())); $this->assertTrue($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'f', array())); } + + public function testSingularize() + { + $this->assertTrue($this->extractor->isWritable(AdderRemoverDummy::class, 'analyses')); + $this->assertTrue($this->extractor->isWritable(AdderRemoverDummy::class, 'feet')); + $this->assertEquals(array('analyses', 'feet'), $this->extractor->getProperties(AdderRemoverDummy::class)); + } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/AdderRemoverDummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/AdderRemoverDummy.php new file mode 100644 index 0000000000..1c2822e578 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/AdderRemoverDummy.php @@ -0,0 +1,29 @@ + + * + * 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 AdderRemoverDummy +{ + private $analyses; + private $feet; + + public function addAnalyse(Dummy $analyse) + { + } + + public function removeFoot(Dummy $foot) + { + } +} diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index dfc345fc53..d2b4d0c147 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -23,7 +23,8 @@ } ], "require": { - "php": ">=5.5.9" + "php": ">=5.5.9", + "symfony/inflector": "~3.1" }, "require-dev": { "symfony/serializer": "~2.8|~3.0",