From e696f5d11841259e8cbe2dea4e90aca46fd564ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 23 Sep 2015 12:26:27 +0200 Subject: [PATCH 1/4] [PropertyInfo] Import the component from dunglas/php-property-info --- composer.json | 7 +- .../PropertyInfo/DoctrineExtractor.php | 156 +++++++ .../PropertyInfo/DoctrineExtractorTest.php | 84 ++++ .../PropertyInfo/Fixtures/DoctrineDummy.php | 66 +++ .../Fixtures/DoctrineRelation.php | 29 ++ src/Symfony/Bridge/Doctrine/composer.json | 2 + .../Extractor/PhpDocExtractor.php | 391 ++++++++++++++++++ .../Extractor/ReflectionExtractor.php | 339 +++++++++++++++ .../Extractor/SerializerExtractor.php | 58 +++ src/Symfony/Component/PropertyInfo/LICENSE | 19 + .../PropertyAccessInfoInterface.php | 42 ++ .../PropertyDescriptionInfoInterface.php | 42 ++ .../Component/PropertyInfo/PropertyInfo.php | 118 ++++++ .../PropertyInfo/PropertyInfoInterface.php | 23 ++ .../PropertyListRetrieverInterface.php | 30 ++ .../PropertyTypeInfoInterface.php | 31 ++ src/Symfony/Component/PropertyInfo/README.md | 14 + .../Tests/Extractors/PhpDocExtractorTest.php | 72 ++++ .../Extractors/ReflectionExtractorTest.php | 122 ++++++ .../Extractors/SerializerExtractorTest.php | 42 ++ .../PropertyInfo/Tests/Fixtures/Dummy.php | 62 +++ .../Tests/Fixtures/DummyExtractor.php | 72 ++++ .../Tests/Fixtures/ParentDummy.php | 73 ++++ .../PropertyInfo/Tests/Fixtures/Php7Dummy.php | 30 ++ .../PropertyInfo/Tests/PropertyInfoTest.php | 71 ++++ .../Component/PropertyInfo/Tests/TypeTest.php | 47 +++ src/Symfony/Component/PropertyInfo/Type.php | 164 ++++++++ .../Component/PropertyInfo/composer.json | 51 +++ .../Component/PropertyInfo/phpunit.xml.dist | 29 ++ 29 files changed, 2285 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php create mode 100644 src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php create mode 100644 src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php create mode 100644 src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php create mode 100644 src/Symfony/Component/PropertyInfo/LICENSE create mode 100644 src/Symfony/Component/PropertyInfo/PropertyAccessInfoInterface.php create mode 100644 src/Symfony/Component/PropertyInfo/PropertyDescriptionInfoInterface.php create mode 100644 src/Symfony/Component/PropertyInfo/PropertyInfo.php create mode 100644 src/Symfony/Component/PropertyInfo/PropertyInfoInterface.php create mode 100644 src/Symfony/Component/PropertyInfo/PropertyListRetrieverInterface.php create mode 100644 src/Symfony/Component/PropertyInfo/PropertyTypeInfoInterface.php create mode 100644 src/Symfony/Component/PropertyInfo/README.md create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Extractors/SerializerExtractorTest.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php7Dummy.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/PropertyInfoTest.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/TypeTest.php create mode 100644 src/Symfony/Component/PropertyInfo/Type.php create mode 100644 src/Symfony/Component/PropertyInfo/composer.json create mode 100644 src/Symfony/Component/PropertyInfo/phpunit.xml.dist diff --git a/composer.json b/composer.json index 67272996c504d..6f207c7b7093f 100644 --- a/composer.json +++ b/composer.json @@ -48,6 +48,7 @@ "symfony/options-resolver": "self.version", "symfony/process": "self.version", "symfony/property-access": "self.version", + "symfony/property-info": "self.version", "symfony/proxy-manager-bridge": "self.version", "symfony/routing": "self.version", "symfony/security": "self.version", @@ -76,7 +77,11 @@ "monolog/monolog": "~1.11", "ircmaxell/password-compat": "~1.0", "ocramius/proxy-manager": "~0.4|~1.0", - "egulias/email-validator": "~1.2" + "egulias/email-validator": "~1.2", + "phpdocumentor/reflection": "~1.0" + }, + "conflict": { + "phpdocumentor/reflection": "<1.0.7" }, "autoload": { "psr-4": { diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php new file mode 100644 index 0000000000000..cb85277fac24a --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\PropertyInfo; + +use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory; +use Doctrine\Common\Persistence\Mapping\MappingException; +use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Symfony\Component\PropertyInfo\PropertyListRetrieverInterface; +use Symfony\Component\PropertyInfo\PropertyTypeInfoInterface; +use Symfony\Component\PropertyInfo\Type; + +/** + * Extracts data using Doctrine ORM and ODM metadata. + * + * @author Kévin Dunglas + */ +class DoctrineExtractor implements PropertyListRetrieverInterface, PropertyTypeInfoInterface +{ + /** + * @var ClassMetadataFactory + */ + private $classMetadataFactory; + + public function __construct(ClassMetadataFactory $classMetadataFactory) + { + $this->classMetadataFactory = $classMetadataFactory; + } + + /** + * {@inheritdoc} + */ + public function getProperties($class, array $context = array()) + { + try { + $metadata = $this->classMetadataFactory->getMetadataFor($class); + } catch (MappingException $exception) { + return; + } + + return array_merge($metadata->getFieldNames(), $metadata->getAssociationNames()); + } + + /** + * {@inheritdoc} + */ + public function getTypes($class, $property, array $context = array()) + { + try { + $metadata = $this->classMetadataFactory->getMetadataFor($class); + } catch (MappingException $exception) { + return; + } + + if ($metadata->hasAssociation($property)) { + $class = $metadata->getAssociationTargetClass($property); + + if ($metadata->isSingleValuedAssociation($property)) { + if ($metadata instanceof ClassMetadataInfo) { + $nullable = isset($metadata->discriminatorColumn['nullable']) ? $metadata->discriminatorColumn['nullable'] : false; + } else { + $nullable = false; + } + + return array(new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $class)); + } + + return array(new Type( + Type::BUILTIN_TYPE_OBJECT, + false, + 'Doctrine\Common\Collections\Collection', + true, + new Type(Type::BUILTIN_TYPE_INT), + new Type(Type::BUILTIN_TYPE_OBJECT, false, $class) + )); + } + + if ($metadata->hasField($property)) { + $typeOfField = $metadata->getTypeOfField($property); + if ($metadata instanceof ClassMetadataInfo) { + $nullable = $metadata->isNullable($property); + } else { + $nullable = false; + } + + switch ($typeOfField) { + case 'date': + // No break + case 'datetime': + // No break + case 'datetimetz': + // No break + case 'time': + return array(new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')); + + case 'array': + return array(new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)); + + case 'simple_array': + return array(new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING))); + + case 'json_array': + return array(new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)); + + default: + return array(new Type($this->getPhpType($typeOfField), $nullable)); + } + } + } + + /** + * Gets the corresponding built-in PHP type. + * + * @param string $doctrineType + * + * @return string + */ + private function getPhpType($doctrineType) + { + switch ($doctrineType) { + case 'smallint': + // No break + case 'bigint': + // No break + case 'integer': + return Type::BUILTIN_TYPE_INT; + + case 'decimal': + return Type::BUILTIN_TYPE_FLOAT; + + case 'text': + // No break + case 'guid': + return Type::BUILTIN_TYPE_STRING; + + case 'boolean': + return Type::BUILTIN_TYPE_BOOL; + + case 'blob': + // No break + case 'binary': + return Type::BUILTIN_TYPE_RESOURCE; + + default: + return $doctrineType; + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php new file mode 100644 index 0000000000000..df6c355895086 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\PropertyInfo\Tests; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Tools\Setup; +use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor; +use Symfony\Component\PropertyInfo\Type; + +/** + * @author Kévin Dunglas + */ +class DoctrineExtractorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var DoctrineExtractor + */ + private $extractor; + + public function setUp() + { + $config = Setup::createAnnotationMetadataConfiguration(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'), true); + $entityManager = EntityManager::create(array('driver' => 'pdo_sqlite'), $config); + + $this->extractor = new DoctrineExtractor($entityManager->getMetadataFactory()); + } + + public function testGetProperties() + { + $this->assertEquals( + array( + 'id', + 'guid', + 'time', + 'json', + 'simpleArray', + 'bool', + 'binary', + 'foo', + 'bar', + ), + $this->extractor->getProperties('Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineDummy') + ); + } + + /** + * @dataProvider typesProvider + */ + public function testExtract($property, array $type = null) + { + $this->assertEquals($type, $this->extractor->getTypes('Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineDummy', $property, array())); + } + + public function typesProvider() + { + return array( + array('id', array(new Type(Type::BUILTIN_TYPE_INT))), + array('guid', array(new Type(Type::BUILTIN_TYPE_STRING))), + array('bool', array(new Type(Type::BUILTIN_TYPE_BOOL))), + array('binary', array(new Type(Type::BUILTIN_TYPE_RESOURCE))), + array('json', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true))), + array('foo', array(new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation'))), + array('bar', array(new Type( + Type::BUILTIN_TYPE_OBJECT, + false, + 'Doctrine\Common\Collections\Collection', + true, + new Type(Type::BUILTIN_TYPE_INT), + new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation') + ))), + array('simpleArray', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)))), + array('notMapped', null), + ); + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php new file mode 100644 index 0000000000000..575d5b28df433 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures; + +use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Entity; +use Doctrine\ORM\Mapping\Id; +use Doctrine\ORM\Mapping\ManyToMany; +use Doctrine\ORM\Mapping\ManyToOne; + +/** + * @Entity + * + * @author Kévin Dunglas + */ +class DoctrineDummy +{ + /** + * @Id + * @Column(type="smallint") + */ + public $id; + /** + * @ManyToOne(targetEntity="DoctrineRelation") + */ + public $foo; + /** + * @ManyToMany(targetEntity="DoctrineRelation") + */ + public $bar; + /** + * @Column(type="guid") + */ + protected $guid; + /** + * @Column(type="time") + */ + private $time; + /** + * @Column(type="json_array") + */ + private $json; + /** + * @Column(type="simple_array") + */ + private $simpleArray; + /** + * @Column(type="boolean") + */ + private $bool; + /** + * @Column(type="binary") + */ + private $binary; + + public $notMapped; +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.php new file mode 100644 index 0000000000000..bfb27e9338d99 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineRelation.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\Bridge\Doctrine\Tests\PropertyInfo\Fixtures; + +use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Id; + +/** + * @Entity + * + * @author Kévin Dunglas + */ +class DoctrineRelation +{ + /** + * @Id + * @Column(type="smallint") + */ + public $id; +} diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index b27949cfaf9b8..bf215f1697bfd 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -26,6 +26,7 @@ "symfony/form": "~2.8|~3.0.0", "symfony/http-kernel": "~2.2|~3.0.0", "symfony/property-access": "~2.3|~3.0.0", + "symfony/property-info": "~2.8|3.0", "symfony/security": "~2.2|~3.0.0", "symfony/expression-language": "~2.2|~3.0.0", "symfony/validator": "~2.5,>=2.5.5|~3.0.0", @@ -37,6 +38,7 @@ "suggest": { "symfony/form": "", "symfony/validator": "", + "symfony/property-info": "", "doctrine/data-fixtures": "", "doctrine/dbal": "", "doctrine/orm": "" diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php new file mode 100644 index 0000000000000..e65f82d68fb0a --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -0,0 +1,391 @@ + + * + * 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 phpDocumentor\Reflection\ClassReflector; +use phpDocumentor\Reflection\DocBlock; +use phpDocumentor\Reflection\FileReflector; +use Symfony\Component\PropertyInfo\PropertyDescriptionInfoInterface; +use Symfony\Component\PropertyInfo\PropertyTypeInfoInterface; +use Symfony\Component\PropertyInfo\Type; + +/** + * Extracts data using a PHPDoc parser. + * + * @author Kévin Dunglas + */ +class PhpDocExtractor implements PropertyDescriptionInfoInterface, PropertyTypeInfoInterface +{ + const PROPERTY = 0; + const ACCESSOR = 1; + const MUTATOR = 2; + + /** + * @var FileReflector[] + */ + private $fileReflectors = array(); + /** + * @var DocBlock[] + */ + private $docBlocks = array(); + + /** + * {@inheritdoc} + */ + public function getShortDescription($class, $property, array $context = array()) + { + list($docBlock) = $this->getDocBlock($class, $property); + if (!$docBlock) { + return; + } + + $shortDescription = $docBlock->getShortDescription(); + if ($shortDescription) { + return $shortDescription; + } + + foreach ($docBlock->getTagsByName('var') as $var) { + $parsedDescription = $var->getParsedDescription(); + + if (isset($parsedDescription[0]) && '' !== $parsedDescription[0]) { + return $parsedDescription[0]; + } + } + } + + /** + * {@inheritdoc} + */ + public function getLongDescription($class, $property, array $context = array()) + { + list($docBlock) = $this->getDocBlock($class, $property); + if (!$docBlock) { + return; + } + + $contents = $docBlock->getLongDescription()->getContents(); + + return '' === $contents ? null : $contents; + } + + /** + * {@inheritdoc} + */ + public function getTypes($class, $property, array $context = array()) + { + list($docBlock, $source, $prefix) = $this->getDocBlock($class, $property); + if (!$docBlock) { + return; + } + + switch ($source) { + case self::PROPERTY: + $tag = 'var'; + break; + + case self::ACCESSOR: + $tag = 'return'; + break; + + case self::MUTATOR: + $tag = 'param'; + break; + } + + $types = array(); + foreach ($docBlock->getTagsByName($tag) as $tag) { + $varTypes = $tag->getTypes(); + + // If null is present, all types are nullable + $nullKey = array_search(Type::BUILTIN_TYPE_NULL, $varTypes); + $nullable = false !== $nullKey; + + // Remove the null type from the type if other types are defined + if ($nullable && count($varTypes) > 1) { + unset($varTypes[$nullKey]); + } + + foreach ($varTypes as $varType) { + $type = $this->createType($varType, $nullable); + if (null !== $type) { + $types[] = $type; + } + } + } + + if (!isset($types[0])) { + return; + } + + if (!in_array($prefix, ReflectionExtractor::$arrayMutatorPrefixes)) { + return $types; + } + + return array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $types[0])); + } + + /** + * Gets the FileReflector associated with the class. + * + * @param \ReflectionClass $reflectionClass + * + * @return FileReflector|null + */ + private function getFileReflector(\ReflectionClass $reflectionClass) + { + if (!($fileName = $reflectionClass->getFileName()) || 'hh' === pathinfo($fileName, PATHINFO_EXTENSION)) { + return; + } + + if (isset($this->fileReflectors[$fileName])) { + return $this->fileReflectors[$fileName]; + } + + $this->fileReflectors[$fileName] = new FileReflector($fileName); + $this->fileReflectors[$fileName]->process(); + + return $this->fileReflectors[$fileName]; + } + + /** + * Gets the DocBlock for this property. + * + * @param string $class + * @param string $property + * + * @return array + */ + private function getDocBlock($class, $property) + { + $propertyHash = sprintf('%s::%s', $class, $property); + + if (isset($this->docBlocks[$propertyHash])) { + return $this->docBlocks[$propertyHash]; + } + + $ucFirstProperty = ucfirst($property); + + switch (true) { + case $docBlock = $this->getDocBlockFromProperty($class, $property): + $data = array($docBlock, self::PROPERTY, null); + break; + + case list($docBlock) = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::ACCESSOR): + $data = array($docBlock, self::ACCESSOR, null); + break; + + case list($docBlock, $prefix) = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::MUTATOR): + $data = array($docBlock, self::MUTATOR, $prefix); + break; + + default: + $data = array(null, null); + } + + return $this->docBlocks[$propertyHash] = $data; + } + + /** + * Gets the DocBlock from a property. + * + * @param string $class + * @param string $property + * + * @return DocBlock|null + */ + private function getDocBlockFromProperty($class, $property) + { + // Use a ReflectionProperty instead of $class to get the parent class if applicable + try { + $reflectionProperty = new \ReflectionProperty($class, $property); + } catch (\ReflectionException $reflectionException) { + return; + } + + $reflectionCLass = $reflectionProperty->getDeclaringClass(); + + $fileReflector = $this->getFileReflector($reflectionCLass); + if (!$fileReflector) { + return; + } + + foreach ($fileReflector->getClasses() as $classReflector) { + $className = $this->getClassName($classReflector); + + if ($className === $reflectionCLass->name) { + foreach ($classReflector->getProperties() as $propertyReflector) { + // strip the $ prefix + $propertyName = substr($propertyReflector->getName(), 1); + + if ($propertyName === $property) { + return $propertyReflector->getDocBlock(); + } + } + } + } + } + + /** + * Gets DocBlock from accessor or mutator method. + * + * @param string $class + * @param string $ucFirstProperty + * @param int $type + * + * @return DocBlock|null + */ + private function getDocBlockFromMethod($class, $ucFirstProperty, $type) + { + $prefixes = $type === self::ACCESSOR ? ReflectionExtractor::$accessorPrefixes : ReflectionExtractor::$mutatorPrefixes; + + foreach ($prefixes as $prefix) { + $methodName = $prefix.$ucFirstProperty; + + try { + $reflectionMethod = new \ReflectionMethod($class, $methodName); + + if ( + (self::ACCESSOR === $type && 0 === $reflectionMethod->getNumberOfRequiredParameters()) || + (self::MUTATOR === $type && $reflectionMethod->getNumberOfParameters() >= 1) + ) { + break; + } + } catch (\ReflectionException $reflectionException) { + // Try the next prefix if the method doesn't exist + } + } + + if (!isset($reflectionMethod)) { + return; + } + + $reflectionClass = $reflectionMethod->getDeclaringClass(); + $fileReflector = $this->getFileReflector($reflectionClass); + + if (!$fileReflector) { + return; + } + + foreach ($fileReflector->getClasses() as $classReflector) { + $className = $this->getClassName($classReflector); + + if ($className === $reflectionClass->name) { + if ($methodReflector = $classReflector->getMethod($methodName)) { + return array($methodReflector->getDocBlock(), $prefix); + } + } + } + } + + /** + * Gets the normalized class name (without trailing backslash). + * + * @param ClassReflector $classReflector + * + * @return string + */ + private function getClassName(ClassReflector $classReflector) + { + $className = $classReflector->getName(); + if ('\\' === $className[0]) { + return substr($className, 1); + } + + return $className; + } + + /** + * Creates a {@see Type} from a PHPDoc type. + * + * @param string $docType + * @param bool $nullable + * + * @return Type|null + */ + private function createType($docType, $nullable) + { + // Cannot guess + if (!$docType || 'mixed' === $docType) { + return; + } + + if ($collection = '[]' === substr($docType, -2)) { + $docType = substr($docType, 0, -2); + } + + $docType = $this->normalizeType($docType); + list($phpType, $class) = $this->getPhpTypeAndClass($docType); + + $array = 'array' === $docType; + + if ($collection || $array) { + if ($array || 'mixed' === $docType) { + $collectionKeyType = null; + $collectionValueType = null; + } else { + $collectionKeyType = new Type(Type::BUILTIN_TYPE_INT); + $collectionValueType = new Type($phpType, false, $class); + } + + return new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, $collectionKeyType, $collectionValueType); + } + + return new Type($phpType, $nullable, $class); + } + + /** + * Normalizes the type. + * + * @param string $docType + * + * @return string + */ + private function normalizeType($docType) + { + switch ($docType) { + case 'integer': + return 'int'; + + case 'boolean': + return 'bool'; + + // real is not part of the PHPDoc standard, so we ignore it + case 'double': + return 'float'; + + case 'callback': + return 'callable'; + + case 'void': + return 'null'; + + default: + return $docType; + } + } + + /** + * Gets an array containing the PHP type and the class. + * + * @param string $docType + * + * @return array + */ + private function getPhpTypeAndClass($docType) + { + if (in_array($docType, Type::$builtinTypes)) { + return array($docType, null); + } + + return array('object', substr($docType, 1)); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php new file mode 100644 index 0000000000000..9b3970297f56d --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -0,0 +1,339 @@ + + * + * 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\PropertyAccessInfoInterface; +use Symfony\Component\PropertyInfo\PropertyListRetrieverInterface; +use Symfony\Component\PropertyInfo\PropertyTypeInfoInterface; +use Symfony\Component\PropertyInfo\Type; + +/** + * Extracts PHP informations using the reflection API. + * + * @author Kévin Dunglas + */ +class ReflectionExtractor implements PropertyListRetrieverInterface, PropertyTypeInfoInterface, PropertyAccessInfoInterface +{ + /** + * @internal + * + * @var string[] + */ + public static $mutatorPrefixes = array('add', 'remove', 'set'); + /** + * @internal + * + * @var string[] + */ + public static $accessorPrefixes = array('is', 'can', 'get'); + /** + * @internal + * + * @var array[] + */ + public static $arrayMutatorPrefixes = array('add', 'remove'); + + /** + * {@inheritdoc} + */ + public function getProperties($class, array $context = array()) + { + try { + $reflectionClass = new \ReflectionClass($class); + } catch (\ReflectionException $reflectionException) { + return; + } + + $properties = array(); + foreach ($reflectionClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflectionProperty) { + $properties[$reflectionProperty->name] = true; + } + + foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { + $propertyName = $this->getPropertyName($reflectionMethod->name); + if ($propertyName) { + $properties[$propertyName] = true; + } + } + + return array_keys($properties); + } + + /** + * {@inheritdoc} + */ + public function getTypes($class, $property, array $context = array()) + { + if ($fromMutator = $this->extractFromMutator($class, $property)) { + return $fromMutator; + } + + if ($fromAccessor = $this->extractFromAccessor($class, $property)) { + return $fromAccessor; + } + } + + /** + * {@inheritdoc} + */ + public function isReadable($class, $property, array $context = array()) + { + if ($this->isPublicProperty($class, $property)) { + return true; + } + + list($reflectionMethod) = $this->getAccessorMethod($class, $property); + + return null !== $reflectionMethod; + } + + /** + * {@inheritdoc} + */ + public function isWritable($class, $property, array $context = array()) + { + if ($this->isPublicProperty($class, $property)) { + return true; + } + + list($reflectionMethod) = $this->getMutatorMethod($class, $property); + + return null !== $reflectionMethod; + } + + /** + * Tries to extract type information from mutators. + * + * @param string $class + * @param string $property + * + * @return Type[]|null + */ + private function extractFromMutator($class, $property) + { + list($reflectionMethod, $prefix) = $this->getMutatorMethod($class, $property); + if (null === $reflectionMethod) { + return; + } + + $reflectionParameters = $reflectionMethod->getParameters(); + $reflectionParameter = $reflectionParameters[0]; + + $arrayMutator = in_array($prefix, self::$arrayMutatorPrefixes); + + if (method_exists($reflectionParameter, 'getType') && $reflectionType = $reflectionParameter->getType()) { + $fromReflectionType = $this->extractFromReflectionType($reflectionType); + + if (!$arrayMutator) { + return array($fromReflectionType); + } + + $phpType = Type::BUILTIN_TYPE_ARRAY; + $collectionKeyType = new Type(Type::BUILTIN_TYPE_INT); + $collectionValueType = $fromReflectionType; + } + + if ($reflectionParameter->isArray()) { + $phpType = Type::BUILTIN_TYPE_ARRAY; + $collection = true; + } + + if ($arrayMutator) { + $collection = true; + $nullable = false; + $collectionNullable = $reflectionParameter->allowsNull(); + } else { + $nullable = $reflectionParameter->allowsNull(); + $collectionNullable = false; + } + + if (!isset($collection)) { + $collection = false; + } + + if (method_exists($reflectionParameter, 'isCallable') && $reflectionParameter->isCallable()) { + $phpType = Type::BUILTIN_TYPE_CALLABLE; + } + + if ($typeHint = $reflectionParameter->getClass()) { + if ($collection) { + $phpType = Type::BUILTIN_TYPE_ARRAY; + $collectionKeyType = new Type(Type::BUILTIN_TYPE_INT); + $collectionValueType = new Type(Type::BUILTIN_TYPE_OBJECT, $collectionNullable, $typeHint->name); + } else { + $phpType = Type::BUILTIN_TYPE_OBJECT; + $typeClass = $typeHint->name; + } + } + + // Nothing useful extracted + if (!isset($phpType)) { + return; + } + + return array( + new Type( + $phpType, + $nullable, + isset($typeClass) ? $typeClass : null, + $collection, + isset($collectionKeyType) ? $collectionKeyType : null, + isset($collectionValueType) ? $collectionValueType : null + ), + ); + } + + /** + * Tries to extract type information from accessors. + * + * @param string $class + * @param string $property + * + * @return Type[]|null + */ + private function extractFromAccessor($class, $property) + { + list($reflectionMethod, $prefix) = $this->getAccessorMethod($class, $property); + if (null === $reflectionMethod) { + return; + } + + if (method_exists($reflectionMethod, 'getReturnType') && $reflectionType = $reflectionMethod->getReturnType()) { + return array($this->extractFromReflectionType($reflectionType)); + } + + if (in_array($prefix, array('is', 'can'))) { + return array(new Type(Type::BUILTIN_TYPE_BOOL)); + } + } + + /** + * Extracts data from the PHP 7 reflection type. + * + * @param \ReflectionType $reflectionType + * + * @return Type + */ + private function extractFromReflectionType(\ReflectionType $reflectionType) + { + $phpTypeOrClass = (string) $reflectionType; + $nullable = $reflectionType->allowsNull(); + + if ($reflectionType->isBuiltin()) { + if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { + $type = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true); + } else { + $type = new Type($phpTypeOrClass, $nullable); + } + } else { + $type = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $phpTypeOrClass); + } + + return $type; + } + + /** + * Does the class have the given public property? + * + * @param string $class + * @param string $property + * + * @return bool + */ + private function isPublicProperty($class, $property) + { + try { + $reflectionProperty = new \ReflectionProperty($class, $property); + + return $reflectionProperty->isPublic(); + } catch (\ReflectionException $reflectionExcetion) { + // Return false if the property doesn't exist + } + + return false; + } + + /** + * Gets the accessor method. + * + * Returns an array with a the instance of \ReflectionMethod as first key + * and the prefix of the method as second or null if not found. + * + * @param string $class + * @param string $property + * + * @return array|null + */ + private function getAccessorMethod($class, $property) + { + $ucProperty = ucfirst($property); + + foreach (self::$accessorPrefixes as $prefix) { + try { + $reflectionMethod = new \ReflectionMethod($class, $prefix.$ucProperty); + + if (0 === $reflectionMethod->getNumberOfRequiredParameters()) { + return array($reflectionMethod, $prefix); + } + } catch (\ReflectionException $reflectionException) { + // Return null if the property doesn't exist + } + } + + return; + } + + /** + * Gets the mutator method. + * + * Returns an array with a the instance of \ReflectionMethod as first key + * and the prefix of the method as second or null if not found. + * + * @param string $class + * @param string $property + * + * @return array + */ + private function getMutatorMethod($class, $property) + { + $ucProperty = ucfirst($property); + + foreach (self::$mutatorPrefixes as $prefix) { + try { + $reflectionMethod = new \ReflectionMethod($class, $prefix.$ucProperty); + + // 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 prefix if the method doesn't exist + } + } + } + + /** + * Extracts a property name from a method name. + * + * @param string $methodName + * + * @return string + */ + private function getPropertyName($methodName) + { + $pattern = implode('|', array_merge(self::$accessorPrefixes, self::$mutatorPrefixes)); + + if (preg_match('/^('.$pattern.')(.+)$/i', $methodName, $matches)) { + return $matches[2]; + } + } +} diff --git a/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php new file mode 100644 index 0000000000000..3ac07e82f95b2 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php @@ -0,0 +1,58 @@ + + * + * 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\PropertyListRetrieverInterface; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; + +/** + * Lists available properties using Symfony Serializer Component metadata. + * + * @author Kévin Dunglas + */ +class SerializerExtractor implements PropertyListRetrieverInterface +{ + /** + * @var ClassMetadataFactoryInterface + */ + private $classMetadataFactory; + + public function __construct(ClassMetadataFactoryInterface $classMetadataFactory) + { + $this->classMetadataFactory = $classMetadataFactory; + } + + /** + * {@inheritdoc} + */ + public function getProperties($class, array $context = array()) + { + if (!isset($context['serializer_groups']) || !is_array($context['serializer_groups'])) { + return; + } + + if (!$this->classMetadataFactory->getMetadataFor($class)) { + return; + } + + $properties = array(); + $serializerClassMetadata = $this->classMetadataFactory->getMetadataFor($class); + + foreach ($serializerClassMetadata->getAttributesMetadata() as $serializerAttributeMetadata) { + if (count(array_intersect($context['serializer_groups'], $serializerAttributeMetadata->getGroups())) > 0) { + $properties[] = $serializerAttributeMetadata->getName(); + } + } + + return $properties; + } +} diff --git a/src/Symfony/Component/PropertyInfo/LICENSE b/src/Symfony/Component/PropertyInfo/LICENSE new file mode 100644 index 0000000000000..a69485974daba --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/PropertyInfo/PropertyAccessInfoInterface.php b/src/Symfony/Component/PropertyInfo/PropertyAccessInfoInterface.php new file mode 100644 index 0000000000000..67468e73d8a6e --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/PropertyAccessInfoInterface.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo; + +/** + * Guesses if the property can be accessed or mutated. + * + * @author Kévin Dunglas + */ +interface PropertyAccessInfoInterface +{ + /** + * Is the property readable? + * + * @param string $class + * @param string $property + * @param array $context + * + * @return bool|null + */ + public function isReadable($class, $property, array $context = array()); + + /** + * Is the property writable? + * + * @param string $class + * @param string $property + * @param array $context + * + * @return bool|null + */ + public function isWritable($class, $property, array $context = array()); +} diff --git a/src/Symfony/Component/PropertyInfo/PropertyDescriptionInfoInterface.php b/src/Symfony/Component/PropertyInfo/PropertyDescriptionInfoInterface.php new file mode 100644 index 0000000000000..a4c1d6a9d3b4a --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/PropertyDescriptionInfoInterface.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo; + +/** + * Description extractor Interface. + * + * @author Kévin Dunglas + */ +interface PropertyDescriptionInfoInterface +{ + /** + * Gets the short description of the property. + * + * @param string $class + * @param string $property + * @param array $context + * + * @return string|null + */ + public function getShortDescription($class, $property, array $context = array()); + + /** + * Gets the long description of the property. + * + * @param string $class + * @param string $property + * @param array $context + * + * @return string|null + */ + public function getLongDescription($class, $property, array $context = array()); +} diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfo.php b/src/Symfony/Component/PropertyInfo/PropertyInfo.php new file mode 100644 index 0000000000000..509cf879feea2 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/PropertyInfo.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo; + +/** + * Default {@see PropertyInfoInterface} implementation. + * + * @author Kévin Dunglas + */ +class PropertyInfo implements PropertyInfoInterface +{ + /** + * @var PropertyListRetrieverInterface[] + */ + private $listExtractors; + /** + * @var PropertyTypeInfoInterface[] + */ + private $typeExtractors; + /** + * @var PropertyDescriptionInfoInterface[] + */ + private $descriptionExtractors; + /** + * @var PropertyAccessInfoInterface[] + */ + private $accessExtractors; + + /** + * @param PropertyListRetrieverInterface[] $listExtractors + * @param PropertyTypeInfoInterface[] $typeExtractors + * @param PropertyDescriptionInfoInterface[] $descriptionExtractors + * @param PropertyAccessInfoInterface[] $accessExtractors + */ + public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array()) + { + $this->listExtractors = $listExtractors; + $this->typeExtractors = $typeExtractors; + $this->descriptionExtractors = $descriptionExtractors; + $this->accessExtractors = $accessExtractors; + } + + /** + * {@inheritdoc} + */ + public function getProperties($class, array $context = array()) + { + return $this->extract($this->listExtractors, 'getProperties', array($class, $context)); + } + + /** + * {@inheritdoc} + */ + public function getShortDescription($class, $property, array $context = array()) + { + return $this->extract($this->descriptionExtractors, 'getShortDescription', array($class, $property, $context)); + } + + /** + * {@inheritdoc} + */ + public function getLongDescription($class, $property, array $context = array()) + { + return $this->extract($this->descriptionExtractors, 'getLongDescription', array($class, $property, $context)); + } + + /** + * {@inheritdoc} + */ + public function getTypes($class, $property, array $context = array()) + { + return $this->extract($this->typeExtractors, 'getTypes', array($class, $property, $context)); + } + + /** + * {@inheritdoc} + */ + public function isReadable($class, $property, array $context = array()) + { + return $this->extract($this->accessExtractors, 'isReadable', array($class, $property, $context)); + } + + /** + * {@inheritdoc} + */ + public function isWritable($class, $property, array $context = array()) + { + return $this->extract($this->accessExtractors, 'isWritable', array($class, $property, $context)); + } + + /** + * Iterates over registered extractors and return the first value found. + * + * @param array $extractors + * @param string $method + * @param array $arguments + * + * @return mixed + */ + private function extract(array $extractors, $method, array $arguments) + { + foreach ($extractors as $extractor) { + $value = call_user_func_array(array($extractor, $method), $arguments); + if (null !== $value) { + return $value; + } + } + } +} diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoInterface.php b/src/Symfony/Component/PropertyInfo/PropertyInfoInterface.php new file mode 100644 index 0000000000000..7fe6b64c13181 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo; + +/** + * Gets info about PHP class properties. + * + * A convenient interface inheriting all specific info interfaces. + * + * @author Kévin Dunglas + */ +interface PropertyInfoInterface extends PropertyTypeInfoInterface, PropertyDescriptionInfoInterface, PropertyAccessInfoInterface, PropertyListRetrieverInterface +{ +} diff --git a/src/Symfony/Component/PropertyInfo/PropertyListRetrieverInterface.php b/src/Symfony/Component/PropertyInfo/PropertyListRetrieverInterface.php new file mode 100644 index 0000000000000..2a7c56c35fb22 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/PropertyListRetrieverInterface.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; + +/** + * Extracts the list of properties available for the given class. + * + * @author Kévin Dunglas + */ +interface PropertyListRetrieverInterface +{ + /** + * Gets the list of properties available for the given class. + * + * @param string $class + * @param array $context + * + * @return string[]|null + */ + public function getProperties($class, array $context = array()); +} diff --git a/src/Symfony/Component/PropertyInfo/PropertyTypeInfoInterface.php b/src/Symfony/Component/PropertyInfo/PropertyTypeInfoInterface.php new file mode 100644 index 0000000000000..e6113f6b5b2fa --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/PropertyTypeInfoInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo; + +/** + * Type Extractor Interface. + * + * @author Kévin Dunglas + */ +interface PropertyTypeInfoInterface +{ + /** + * Gets types of a property. + * + * @param string $class + * @param string $property + * @param array $context + * + * @return Type[]|null + */ + public function getTypes($class, $property, array $context = array()); +} diff --git a/src/Symfony/Component/PropertyInfo/README.md b/src/Symfony/Component/PropertyInfo/README.md new file mode 100644 index 0000000000000..0f1af40190288 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/README.md @@ -0,0 +1,14 @@ +PropertyInfo Component +====================== + +PropertyInfo extracts information about PHP class' properties using metadata +of popular sources. + +Resources +--------- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/PropertyInfo/ + $ composer install + $ phpunit diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php new file mode 100644 index 0000000000000..3422ca57878b5 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests\PhpDocExtractors; + +use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; +use Symfony\Component\PropertyInfo\Type; + +/** + * @author Kévin Dunglas + */ +class PhpDocExtractorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var PhpDocPropertyInfo + */ + private $extractor; + + public function setUp() + { + $this->extractor = new PhpDocExtractor(); + } + + /** + * @dataProvider typesProvider + */ + public function testExtract($property, array $type = null, $shortDescription, $longDescription) + { + $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); + $this->assertSame($shortDescription, $this->extractor->getShortDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); + $this->assertSame($longDescription, $this->extractor->getLongDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property)); + } + + public function typesProvider() + { + 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', array(new Type(Type::BUILTIN_TYPE_INT)), 'A.', null), + array('b', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy')), '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), + ); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php new file mode 100644 index 0000000000000..ba00d1c792cac --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests\Extractor; + +use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; +use Symfony\Component\PropertyInfo\Type; + +/** + * @author Kévin Dunglas + */ +class ReflectionExtractorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var ReflectionExtractor + */ + private $extractor; + + public function setUp() + { + $this->extractor = new ReflectionExtractor(); + } + + public function testGetProperties() + { + $this->assertEquals( + array( + 'bal', + 'parent', + 'collection', + 'foo', + 'foo2', + 'foo3', + 'foo4', + 'foo5', + 'files', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + ), + $this->extractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy') + ); + } + + /** + * @dataProvider typesProvider + */ + public function testExtractors($property, array $type = null) + { + $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property, array())); + } + + public function typesProvider() + { + return array( + array('a', null), + array('b', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy'))), + array('c', array(new Type(Type::BUILTIN_TYPE_BOOL))), + array('d', array(new Type(Type::BUILTIN_TYPE_BOOL))), + array('e', 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')))), + ); + } + + /** + * @dataProvider php7TypesProvider + */ + public function testExtractPhp7Type($property, array $type = null) + { + if (!method_exists('\ReflectionMethod', 'getReturnType')) { + $this->markTestSkipped('Available only with PHP 7 and superior.'); + } + + $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php7Dummy', $property, array())); + } + + public function php7TypesProvider() + { + return array( + array('foo', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true))), + array('bar', array(new Type(Type::BUILTIN_TYPE_INT))), + array('baz', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)))), + ); + } + + public function testIsReadable() + { + $this->assertFalse($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'bar', array())); + $this->assertFalse($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'baz', array())); + $this->assertTrue($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'parent', array())); + $this->assertTrue($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'a', array())); + $this->assertFalse($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'b', array())); + $this->assertTrue($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'c', array())); + $this->assertTrue($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'd', array())); + $this->assertFalse($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'e', array())); + $this->assertFalse($this->extractor->isReadable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'f', array())); + } + + public function testIsWritable() + { + $this->assertFalse($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'bar', array())); + $this->assertFalse($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'baz', array())); + $this->assertTrue($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'parent', array())); + $this->assertFalse($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'a', array())); + $this->assertTrue($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'b', array())); + $this->assertFalse($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'c', array())); + $this->assertFalse($this->extractor->isWritable('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', 'd', array())); + $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())); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/SerializerExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/SerializerExtractorTest.php new file mode 100644 index 0000000000000..c170f2237add9 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/SerializerExtractorTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\PropertyInfo\Tests\Extractors; + +use Doctrine\Common\Annotations\AnnotationReader; +use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor; +use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; +use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; + +/** + * @author Kévin Dunglas + */ +class SerializerExtractorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var SerializerExtractor + */ + private $extractor; + + public function setUp() + { + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $this->extractor = new SerializerExtractor($classMetadataFactory); + } + + public function testGetProperties() + { + $this->assertEquals( + array('collection'), + $this->extractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', array('serializer_groups' => array('a'))) + ); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php new file mode 100644 index 0000000000000..9d02b372e7bf9 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -0,0 +1,62 @@ + + * + * 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; + +use Symfony\Component\Serializer\Annotation\Groups; + +/** + * @author Kévin Dunglas + */ +class Dummy extends ParentDummy +{ + /** + * @var string This is bar. + */ + private $bar; + /** + * Should be used. + * + * @var int Should be ignored. + */ + protected $baz; + /** + * @var \DateTime + */ + public $bal; + /** + * @var ParentDummy + */ + public $parent; + /** + * @var \DateTime[] + * @Groups({"a", "b"}) + */ + public $collection; + + /** + * A. + * + * @return int + */ + public function getA() + { + } + + /** + * B. + * + * @param ParentDummy|null $parent + */ + public function setB(ParentDummy $parent = null) + { + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php new file mode 100644 index 0000000000000..2fc01c552f587 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php @@ -0,0 +1,72 @@ + + * + * 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; + +use Symfony\Component\PropertyInfo\PropertyAccessInfoInterface; +use Symfony\Component\PropertyInfo\PropertyDescriptionInfoInterface; +use Symfony\Component\PropertyInfo\PropertyListRetrieverInterface; +use Symfony\Component\PropertyInfo\PropertyTypeInfoInterface; +use Symfony\Component\PropertyInfo\Type; + +/** + * @author Kévin Dunglas + */ +class DummyExtractor implements PropertyListRetrieverInterface, PropertyDescriptionInfoInterface, PropertyTypeInfoInterface, PropertyAccessInfoInterface +{ + /** + * {@inheritdoc} + */ + public function getShortDescription($class, $property, array $context = array()) + { + return 'short'; + } + + /** + * {@inheritdoc} + */ + public function getLongDescription($class, $property, array $context = array()) + { + return 'long'; + } + + /** + * {@inheritdoc} + */ + public function getTypes($class, $property, array $context = array()) + { + return array(new Type(Type::BUILTIN_TYPE_INT)); + } + + /** + * {@inheritdoc} + */ + public function isReadable($class, $property, array $context = array()) + { + return true; + } + + /** + * {@inheritdoc} + */ + public function isWritable($class, $property, array $context = array()) + { + return true; + } + + /** + * {@inheritdoc} + */ + public function getProperties($class, array $context = array()) + { + return array('a', 'b'); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php new file mode 100644 index 0000000000000..c405fd77fa2af --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php @@ -0,0 +1,73 @@ + + * + * 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 ParentDummy +{ + /** + * Short description. + * + * Long description. + */ + public $foo; + /** + * @var float + */ + public $foo2; + /** + * @var callback + */ + public $foo3; + /** + * @var void + */ + public $foo4; + /** + * @var mixed + */ + public $foo5; + /** + * @var \SplFileInfo[]|resource + */ + public $files; + + /** + * @return bool|null + */ + public function isC() + { + } + + /** + * @return bool + */ + public function canD() + { + } + + /** + * @param resource $e + */ + public function addE($e) + { + } + + /** + * @param \DateTime $f + */ + public function removeF(\DateTime $f) + { + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php7Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php7Dummy.php new file mode 100644 index 0000000000000..cd5ba380d9d53 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php7Dummy.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\Tests\Fixtures; + +/** + * @author Kévin Dunglas + */ +class Php7Dummy +{ + public function getFoo(): array + { + } + + public function setBar(int $bar) + { + } + + public function addBaz(string $baz) + { + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoTest.php new file mode 100644 index 0000000000000..b505d2758c260 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\PropertyInfo\Tests; + +use Symfony\Component\PropertyInfo\PropertyInfo; +use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyExtractor; +use Symfony\Component\PropertyInfo\Type; + +/** + * @author Kévin Dunglas + */ +class PropertyInfoTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var PropertyInfo + */ + private $propertyInfo; + + public function setUp() + { + $extractors = array(new DummyExtractor()); + $this->propertyInfo = new PropertyInfo($extractors, $extractors, $extractors, $extractors); + } + + public function testInstanceOf() + { + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyInfoInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyTypeInfoInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyDescriptionInfoInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyAccessInfoInterface', $this->propertyInfo); + } + + public function testGetShortDescription() + { + $this->assertSame('short', $this->propertyInfo->getShortDescription('Foo', 'bar', array())); + } + + public function testGetLongDescription() + { + $this->assertSame('long', $this->propertyInfo->getLongDescription('Foo', 'bar', array())); + } + + public function testGetTypes() + { + $this->assertEquals(array(new Type(Type::BUILTIN_TYPE_INT)), $this->propertyInfo->getTypes('Foo', 'bar', array())); + } + + public function testIsReadable() + { + $this->assertTrue($this->propertyInfo->isReadable('Foo', 'bar', array())); + } + + public function testIsWritable() + { + $this->assertTrue($this->propertyInfo->isWritable('Foo', 'bar', array())); + } + + public function testGetProperties() + { + $this->assertEquals(array('a', 'b'), $this->propertyInfo->getProperties('Foo')); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php b/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php new file mode 100644 index 0000000000000..d8e61057b3d62 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\PropertyInfo\Tests; + +use Symfony\Component\PropertyInfo\Type; + +/** + * @author Kévin Dunglas + */ +class TypeTest extends \PHPUnit_Framework_TestCase +{ + public function testConstruct() + { + $type = new Type('object', true, 'ArrayObject', true, new Type('int'), new Type('string')); + + $this->assertEquals(Type::BUILTIN_TYPE_OBJECT, $type->getBuiltinType()); + $this->assertTrue($type->isNullable()); + $this->assertEquals('ArrayObject', $type->getClassName()); + $this->assertTrue($type->isCollection()); + + $collectionKeyType = $type->getCollectionKeyType(); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\Type', $collectionKeyType); + $this->assertEquals(Type::BUILTIN_TYPE_INT, $collectionKeyType->getBuiltinType()); + + $collectionValueType = $type->getCollectionValueType(); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\Type', $collectionValueType); + $this->assertEquals(Type::BUILTIN_TYPE_STRING, $collectionValueType->getBuiltinType()); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage "foo" is not a PHP valid type. + */ + public function testInvalidType() + { + new Type('foo'); + } +} diff --git a/src/Symfony/Component/PropertyInfo/Type.php b/src/Symfony/Component/PropertyInfo/Type.php new file mode 100644 index 0000000000000..0ca80199fc49c --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Type.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo; + +/** + * Type value object (immutable). + * + * @author Kévin Dunglas + */ +class Type +{ + const BUILTIN_TYPE_INT = 'int'; + const BUILTIN_TYPE_FLOAT = 'float'; + const BUILTIN_TYPE_STRING = 'string'; + const BUILTIN_TYPE_BOOL = 'bool'; + const BUILTIN_TYPE_RESOURCE = 'resource'; + const BUILTIN_TYPE_OBJECT = 'object'; + const BUILTIN_TYPE_ARRAY = 'array'; + const BUILTIN_TYPE_NULL = 'null'; + const BUILTIN_TYPE_CALLABLE = 'callable'; + + /** + * List of PHP builtin types. + * + * @var string[] + */ + public static $builtinTypes = array( + self::BUILTIN_TYPE_INT, + self::BUILTIN_TYPE_FLOAT, + self::BUILTIN_TYPE_STRING, + self::BUILTIN_TYPE_BOOL, + self::BUILTIN_TYPE_RESOURCE, + self::BUILTIN_TYPE_OBJECT, + self::BUILTIN_TYPE_ARRAY, + self::BUILTIN_TYPE_CALLABLE, + self::BUILTIN_TYPE_NULL, + ); + + /** + * @var string + */ + private $builtinType; + /** + * @var bool + */ + private $nullable; + /** + * @var string|null + */ + private $class; + /** + * @var bool + */ + private $collection; + /** + * @var Type|null + */ + private $collectionKeyType; + /** + * @var Type|null + */ + private $collectionValueType; + + /** + * @param string $builtinType + * @param bool $nullable + * @param string|null $class + * @param bool $collection + * @param Type|null $collectionKeyType + * @param Type|null $collectionValueType + * + * @throws \InvalidArgumentException + */ + public function __construct($builtinType, $nullable = false, $class = null, $collection = false, Type $collectionKeyType = null, Type $collectionValueType = null) + { + if (!in_array($builtinType, self::$builtinTypes)) { + throw new \InvalidArgumentException(sprintf('"%s" is not a PHP valid type.', $builtinType)); + } + + $this->builtinType = $builtinType; + $this->nullable = $nullable; + $this->class = $class; + $this->collection = $collection; + $this->collectionKeyType = $collectionKeyType; + $this->collectionValueType = $collectionValueType; + } + + /** + * Gets built-in type. + * + * Can be bool, int, float, string, array, object, resource, null or callback. + * + * @return string + */ + public function getBuiltinType() + { + return $this->builtinType; + } + + /** + * Allows null value? + * + * @return bool + */ + public function isNullable() + { + return $this->nullable; + } + + /** + * Gets the class name. + * + * Only applicable if the built-in type is object. + * + * @return string|null + */ + public function getClassName() + { + return $this->class; + } + + /** + * Is collection? + * + * @return bool + */ + public function isCollection() + { + return $this->collection; + } + + /** + * Gets collection key type. + * + * Only applicable for a collection type. + * + * @return Type|null + */ + public function getCollectionKeyType() + { + return $this->collectionKeyType; + } + + /** + * Gets collection value type. + * + * Only applicable for a collection type. + * + * @return Type|null + */ + public function getCollectionValueType() + { + return $this->collectionValueType; + } +} diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json new file mode 100644 index 0000000000000..b40d0b50e55fd --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -0,0 +1,51 @@ +{ + "name": "symfony/property-info", + "type": "library", + "description": "Symfony Property Info Component", + "keywords": [ + "property", + "type", + "PHPDoc", + "symfony", + "validator", + "doctrine" + ], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7", + "symfony/serializer": "~2.7", + "phpdocumentor/reflection": "~1.0", + "doctrine/annotations": "~1.0" + }, + "conflict": { + "phpdocumentor/reflection": "<1.0.7" + }, + "suggest": { + "symfony/doctrine-bridge": "To use Doctrine metadata", + "phpdocumentor/reflection": "To use the PHPDoc", + "symfony/serializer": "To use Serializer metadata" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\PropertyInfo\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + } +} diff --git a/src/Symfony/Component/PropertyInfo/phpunit.xml.dist b/src/Symfony/Component/PropertyInfo/phpunit.xml.dist new file mode 100644 index 0000000000000..518e472db7488 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + From d217d88ba532bd2edbab4576debeb1964014e384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 23 Sep 2015 16:11:23 +0200 Subject: [PATCH 2/4] CS --- .../Tests/PropertyInfo/Fixtures/DoctrineDummy.php | 8 ++++++++ .../Component/PropertyInfo/Extractor/PhpDocExtractor.php | 1 + .../PropertyInfo/Extractor/ReflectionExtractor.php | 2 ++ src/Symfony/Component/PropertyInfo/PropertyInfo.php | 3 +++ .../Component/PropertyInfo/Tests/Fixtures/Dummy.php | 4 ++++ .../Component/PropertyInfo/Tests/Fixtures/ParentDummy.php | 5 +++++ src/Symfony/Component/PropertyInfo/Tests/TypeTest.php | 2 +- src/Symfony/Component/PropertyInfo/Type.php | 2 +- 8 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php index 575d5b28df433..864bd78407c48 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineDummy.php @@ -29,34 +29,42 @@ class DoctrineDummy * @Column(type="smallint") */ public $id; + /** * @ManyToOne(targetEntity="DoctrineRelation") */ public $foo; + /** * @ManyToMany(targetEntity="DoctrineRelation") */ public $bar; + /** * @Column(type="guid") */ protected $guid; + /** * @Column(type="time") */ private $time; + /** * @Column(type="json_array") */ private $json; + /** * @Column(type="simple_array") */ private $simpleArray; + /** * @Column(type="boolean") */ private $bool; + /** * @Column(type="binary") */ diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index e65f82d68fb0a..0eb3b28c40ab1 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -33,6 +33,7 @@ class PhpDocExtractor implements PropertyDescriptionInfoInterface, PropertyTypeI * @var FileReflector[] */ private $fileReflectors = array(); + /** * @var DocBlock[] */ diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 9b3970297f56d..d67f8eb897fae 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -29,12 +29,14 @@ class ReflectionExtractor implements PropertyListRetrieverInterface, PropertyTyp * @var string[] */ public static $mutatorPrefixes = array('add', 'remove', 'set'); + /** * @internal * * @var string[] */ public static $accessorPrefixes = array('is', 'can', 'get'); + /** * @internal * diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfo.php b/src/Symfony/Component/PropertyInfo/PropertyInfo.php index 509cf879feea2..b5b726c5aadee 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfo.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfo.php @@ -22,14 +22,17 @@ class PropertyInfo implements PropertyInfoInterface * @var PropertyListRetrieverInterface[] */ private $listExtractors; + /** * @var PropertyTypeInfoInterface[] */ private $typeExtractors; + /** * @var PropertyDescriptionInfoInterface[] */ private $descriptionExtractors; + /** * @var PropertyAccessInfoInterface[] */ diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php index 9d02b372e7bf9..8e80c0b59a9ae 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -22,20 +22,24 @@ class Dummy extends ParentDummy * @var string This is bar. */ private $bar; + /** * Should be used. * * @var int Should be ignored. */ protected $baz; + /** * @var \DateTime */ public $bal; + /** * @var ParentDummy */ public $parent; + /** * @var \DateTime[] * @Groups({"a", "b"}) diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php index c405fd77fa2af..330496827cfc4 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php @@ -22,22 +22,27 @@ class ParentDummy * Long description. */ public $foo; + /** * @var float */ public $foo2; + /** * @var callback */ public $foo3; + /** * @var void */ public $foo4; + /** * @var mixed */ public $foo5; + /** * @var \SplFileInfo[]|resource */ diff --git a/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php b/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php index d8e61057b3d62..7663cfc63684e 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/TypeTest.php @@ -38,7 +38,7 @@ public function testConstruct() /** * @expectedException \InvalidArgumentException - * @expectedExceptionMessage "foo" is not a PHP valid type. + * @expectedExceptionMessage "foo" is not a valid PHP type. */ public function testInvalidType() { diff --git a/src/Symfony/Component/PropertyInfo/Type.php b/src/Symfony/Component/PropertyInfo/Type.php index 0ca80199fc49c..749aa5b9cd0a2 100644 --- a/src/Symfony/Component/PropertyInfo/Type.php +++ b/src/Symfony/Component/PropertyInfo/Type.php @@ -83,7 +83,7 @@ class Type public function __construct($builtinType, $nullable = false, $class = null, $collection = false, Type $collectionKeyType = null, Type $collectionValueType = null) { if (!in_array($builtinType, self::$builtinTypes)) { - throw new \InvalidArgumentException(sprintf('"%s" is not a PHP valid type.', $builtinType)); + throw new \InvalidArgumentException(sprintf('"%s" is not a valid PHP type.', $builtinType)); } $this->builtinType = $builtinType; From 6586800ac6d49d89e7c06d927851f6c77d398c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 24 Sep 2015 19:22:23 +0200 Subject: [PATCH 3/4] Another bunch of CS fixes --- composer.json | 2 +- .../Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php | 9 +-------- .../Tests/Extractors/PhpDocExtractorTest.php | 2 +- src/Symfony/Component/PropertyInfo/Type.php | 5 +++++ src/Symfony/Component/PropertyInfo/composer.json | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 6f207c7b7093f..c1b8e8951a5a0 100644 --- a/composer.json +++ b/composer.json @@ -78,7 +78,7 @@ "ircmaxell/password-compat": "~1.0", "ocramius/proxy-manager": "~0.4|~1.0", "egulias/email-validator": "~1.2", - "phpdocumentor/reflection": "~1.0" + "phpdocumentor/reflection": "^1.0.7" }, "conflict": { "phpdocumentor/reflection": "<1.0.7" diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index cb85277fac24a..826ce7ebd8434 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -85,19 +85,12 @@ public function getTypes($class, $property, array $context = array()) if ($metadata->hasField($property)) { $typeOfField = $metadata->getTypeOfField($property); - if ($metadata instanceof ClassMetadataInfo) { - $nullable = $metadata->isNullable($property); - } else { - $nullable = false; - } + $nullable = $metadata instanceof ClassMetadataInfo && $metadata->isNullable($property); switch ($typeOfField) { case 'date': - // No break case 'datetime': - // No break case 'datetimetz': - // No break case 'time': return array(new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime')); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php index 3422ca57878b5..2a1abd75095f9 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php @@ -20,7 +20,7 @@ class PhpDocExtractorTest extends \PHPUnit_Framework_TestCase { /** - * @var PhpDocPropertyInfo + * @var PhpDocExtractor */ private $extractor; diff --git a/src/Symfony/Component/PropertyInfo/Type.php b/src/Symfony/Component/PropertyInfo/Type.php index 749aa5b9cd0a2..8a55a7cbc29e4 100644 --- a/src/Symfony/Component/PropertyInfo/Type.php +++ b/src/Symfony/Component/PropertyInfo/Type.php @@ -49,22 +49,27 @@ class Type * @var string */ private $builtinType; + /** * @var bool */ private $nullable; + /** * @var string|null */ private $class; + /** * @var bool */ private $collection; + /** * @var Type|null */ private $collectionKeyType; + /** * @var Type|null */ diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index b40d0b50e55fd..a9826d42d71c9 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -28,7 +28,7 @@ "require-dev": { "symfony/phpunit-bridge": "~2.7", "symfony/serializer": "~2.7", - "phpdocumentor/reflection": "~1.0", + "phpdocumentor/reflection": "^1.0.7", "doctrine/annotations": "~1.0" }, "conflict": { From e75d1f1f7e31c72627f61983dd93b2fa97d442f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 25 Sep 2015 14:13:43 +0200 Subject: [PATCH 4/4] [PropertyInfo] Rename classes and interfaces --- .../PropertyInfo/DoctrineExtractor.php | 6 +++--- .../Extractor/PhpDocExtractor.php | 6 +++--- .../Extractor/ReflectionExtractor.php | 8 ++++---- .../Extractor/SerializerExtractor.php | 4 ++-- ...p => PropertyAccessExtractorInterface.php} | 2 +- ...PropertyDescriptionExtractorInterface.php} | 2 +- ...ertyInfo.php => PropertyInfoExtractor.php} | 20 +++++++++---------- ...php => PropertyInfoExtractorInterface.php} | 2 +- ...php => PropertyListExtractorInterface.php} | 2 +- ...php => PropertyTypeExtractorInterface.php} | 2 +- .../Tests/Fixtures/DummyExtractor.php | 10 +++++----- ...Test.php => PropertyInfoExtractorTest.php} | 16 +++++++-------- 12 files changed, 40 insertions(+), 40 deletions(-) rename src/Symfony/Component/PropertyInfo/{PropertyAccessInfoInterface.php => PropertyAccessExtractorInterface.php} (95%) rename src/Symfony/Component/PropertyInfo/{PropertyDescriptionInfoInterface.php => PropertyDescriptionExtractorInterface.php} (95%) rename src/Symfony/Component/PropertyInfo/{PropertyInfo.php => PropertyInfoExtractor.php} (82%) rename src/Symfony/Component/PropertyInfo/{PropertyInfoInterface.php => PropertyInfoExtractorInterface.php} (71%) rename src/Symfony/Component/PropertyInfo/{PropertyListRetrieverInterface.php => PropertyListExtractorInterface.php} (94%) rename src/Symfony/Component/PropertyInfo/{PropertyTypeInfoInterface.php => PropertyTypeExtractorInterface.php} (93%) rename src/Symfony/Component/PropertyInfo/Tests/{PropertyInfoTest.php => PropertyInfoExtractorTest.php} (78%) diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 826ce7ebd8434..dc22e235959bd 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -14,8 +14,8 @@ use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory; use Doctrine\Common\Persistence\Mapping\MappingException; use Doctrine\ORM\Mapping\ClassMetadataInfo; -use Symfony\Component\PropertyInfo\PropertyListRetrieverInterface; -use Symfony\Component\PropertyInfo\PropertyTypeInfoInterface; +use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\Type; /** @@ -23,7 +23,7 @@ * * @author Kévin Dunglas */ -class DoctrineExtractor implements PropertyListRetrieverInterface, PropertyTypeInfoInterface +class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface { /** * @var ClassMetadataFactory diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index 0eb3b28c40ab1..0e10fcbc13b10 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -14,8 +14,8 @@ use phpDocumentor\Reflection\ClassReflector; use phpDocumentor\Reflection\DocBlock; use phpDocumentor\Reflection\FileReflector; -use Symfony\Component\PropertyInfo\PropertyDescriptionInfoInterface; -use Symfony\Component\PropertyInfo\PropertyTypeInfoInterface; +use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\Type; /** @@ -23,7 +23,7 @@ * * @author Kévin Dunglas */ -class PhpDocExtractor implements PropertyDescriptionInfoInterface, PropertyTypeInfoInterface +class PhpDocExtractor implements PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface { const PROPERTY = 0; const ACCESSOR = 1; diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index d67f8eb897fae..322b645b80e58 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -11,9 +11,9 @@ namespace Symfony\Component\PropertyInfo\Extractor; -use Symfony\Component\PropertyInfo\PropertyAccessInfoInterface; -use Symfony\Component\PropertyInfo\PropertyListRetrieverInterface; -use Symfony\Component\PropertyInfo\PropertyTypeInfoInterface; +use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\Type; /** @@ -21,7 +21,7 @@ * * @author Kévin Dunglas */ -class ReflectionExtractor implements PropertyListRetrieverInterface, PropertyTypeInfoInterface, PropertyAccessInfoInterface +class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface { /** * @internal diff --git a/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php index 3ac07e82f95b2..b7edb8fa246b0 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php @@ -11,7 +11,7 @@ namespace Symfony\Component\PropertyInfo\Extractor; -use Symfony\Component\PropertyInfo\PropertyListRetrieverInterface; +use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface; /** @@ -19,7 +19,7 @@ * * @author Kévin Dunglas */ -class SerializerExtractor implements PropertyListRetrieverInterface +class SerializerExtractor implements PropertyListExtractorInterface { /** * @var ClassMetadataFactoryInterface diff --git a/src/Symfony/Component/PropertyInfo/PropertyAccessInfoInterface.php b/src/Symfony/Component/PropertyInfo/PropertyAccessExtractorInterface.php similarity index 95% rename from src/Symfony/Component/PropertyInfo/PropertyAccessInfoInterface.php rename to src/Symfony/Component/PropertyInfo/PropertyAccessExtractorInterface.php index 67468e73d8a6e..ecf44d9d656c7 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyAccessInfoInterface.php +++ b/src/Symfony/Component/PropertyInfo/PropertyAccessExtractorInterface.php @@ -16,7 +16,7 @@ * * @author Kévin Dunglas */ -interface PropertyAccessInfoInterface +interface PropertyAccessExtractorInterface { /** * Is the property readable? diff --git a/src/Symfony/Component/PropertyInfo/PropertyDescriptionInfoInterface.php b/src/Symfony/Component/PropertyInfo/PropertyDescriptionExtractorInterface.php similarity index 95% rename from src/Symfony/Component/PropertyInfo/PropertyDescriptionInfoInterface.php rename to src/Symfony/Component/PropertyInfo/PropertyDescriptionExtractorInterface.php index a4c1d6a9d3b4a..a2e98d0febb29 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyDescriptionInfoInterface.php +++ b/src/Symfony/Component/PropertyInfo/PropertyDescriptionExtractorInterface.php @@ -16,7 +16,7 @@ * * @author Kévin Dunglas */ -interface PropertyDescriptionInfoInterface +interface PropertyDescriptionExtractorInterface { /** * Gets the short description of the property. diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfo.php b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php similarity index 82% rename from src/Symfony/Component/PropertyInfo/PropertyInfo.php rename to src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php index b5b726c5aadee..942318af605d8 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfo.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php @@ -12,37 +12,37 @@ namespace Symfony\Component\PropertyInfo; /** - * Default {@see PropertyInfoInterface} implementation. + * Default {@see PropertyInfoExtractorInterface} implementation. * * @author Kévin Dunglas */ -class PropertyInfo implements PropertyInfoInterface +class PropertyInfoExtractor implements PropertyInfoExtractorInterface { /** - * @var PropertyListRetrieverInterface[] + * @var PropertyListExtractorInterface[] */ private $listExtractors; /** - * @var PropertyTypeInfoInterface[] + * @var PropertyTypeExtractorInterface[] */ private $typeExtractors; /** - * @var PropertyDescriptionInfoInterface[] + * @var PropertyDescriptionExtractorInterface[] */ private $descriptionExtractors; /** - * @var PropertyAccessInfoInterface[] + * @var PropertyAccessExtractorInterface[] */ private $accessExtractors; /** - * @param PropertyListRetrieverInterface[] $listExtractors - * @param PropertyTypeInfoInterface[] $typeExtractors - * @param PropertyDescriptionInfoInterface[] $descriptionExtractors - * @param PropertyAccessInfoInterface[] $accessExtractors + * @param PropertyListExtractorInterface[] $listExtractors + * @param PropertyTypeExtractorInterface[] $typeExtractors + * @param PropertyDescriptionExtractorInterface[] $descriptionExtractors + * @param PropertyAccessExtractorInterface[] $accessExtractors */ public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array()) { diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoInterface.php b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorInterface.php similarity index 71% rename from src/Symfony/Component/PropertyInfo/PropertyInfoInterface.php rename to src/Symfony/Component/PropertyInfo/PropertyInfoExtractorInterface.php index 7fe6b64c13181..8893018653f36 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoInterface.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractorInterface.php @@ -18,6 +18,6 @@ * * @author Kévin Dunglas */ -interface PropertyInfoInterface extends PropertyTypeInfoInterface, PropertyDescriptionInfoInterface, PropertyAccessInfoInterface, PropertyListRetrieverInterface +interface PropertyInfoExtractorInterface extends PropertyTypeExtractorInterface, PropertyDescriptionExtractorInterface, PropertyAccessExtractorInterface, PropertyListExtractorInterface { } diff --git a/src/Symfony/Component/PropertyInfo/PropertyListRetrieverInterface.php b/src/Symfony/Component/PropertyInfo/PropertyListExtractorInterface.php similarity index 94% rename from src/Symfony/Component/PropertyInfo/PropertyListRetrieverInterface.php rename to src/Symfony/Component/PropertyInfo/PropertyListExtractorInterface.php index 2a7c56c35fb22..1faae33d02531 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyListRetrieverInterface.php +++ b/src/Symfony/Component/PropertyInfo/PropertyListExtractorInterface.php @@ -16,7 +16,7 @@ * * @author Kévin Dunglas */ -interface PropertyListRetrieverInterface +interface PropertyListExtractorInterface { /** * Gets the list of properties available for the given class. diff --git a/src/Symfony/Component/PropertyInfo/PropertyTypeInfoInterface.php b/src/Symfony/Component/PropertyInfo/PropertyTypeExtractorInterface.php similarity index 93% rename from src/Symfony/Component/PropertyInfo/PropertyTypeInfoInterface.php rename to src/Symfony/Component/PropertyInfo/PropertyTypeExtractorInterface.php index e6113f6b5b2fa..8aa08b4e85e5e 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyTypeInfoInterface.php +++ b/src/Symfony/Component/PropertyInfo/PropertyTypeExtractorInterface.php @@ -16,7 +16,7 @@ * * @author Kévin Dunglas */ -interface PropertyTypeInfoInterface +interface PropertyTypeExtractorInterface { /** * Gets types of a property. diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php index 2fc01c552f587..cfabcf2a90219 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyExtractor.php @@ -11,16 +11,16 @@ namespace Symfony\Component\PropertyInfo\Tests\Fixtures; -use Symfony\Component\PropertyInfo\PropertyAccessInfoInterface; -use Symfony\Component\PropertyInfo\PropertyDescriptionInfoInterface; -use Symfony\Component\PropertyInfo\PropertyListRetrieverInterface; -use Symfony\Component\PropertyInfo\PropertyTypeInfoInterface; +use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\Type; /** * @author Kévin Dunglas */ -class DummyExtractor implements PropertyListRetrieverInterface, PropertyDescriptionInfoInterface, PropertyTypeInfoInterface, PropertyAccessInfoInterface +class DummyExtractor implements PropertyListExtractorInterface, PropertyDescriptionExtractorInterface, PropertyTypeExtractorInterface, PropertyAccessExtractorInterface { /** * {@inheritdoc} diff --git a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoTest.php b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php similarity index 78% rename from src/Symfony/Component/PropertyInfo/Tests/PropertyInfoTest.php rename to src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php index b505d2758c260..84e4af5c89ef6 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/PropertyInfoExtractorTest.php @@ -11,32 +11,32 @@ namespace Symfony\Component\PropertyInfo\PropertyInfo\Tests; -use Symfony\Component\PropertyInfo\PropertyInfo; +use Symfony\Component\PropertyInfo\PropertyInfoExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyExtractor; use Symfony\Component\PropertyInfo\Type; /** * @author Kévin Dunglas */ -class PropertyInfoTest extends \PHPUnit_Framework_TestCase +class PropertyInfoExtractorTest extends \PHPUnit_Framework_TestCase { /** - * @var PropertyInfo + * @var PropertyInfoExtractor */ private $propertyInfo; public function setUp() { $extractors = array(new DummyExtractor()); - $this->propertyInfo = new PropertyInfo($extractors, $extractors, $extractors, $extractors); + $this->propertyInfo = new PropertyInfoExtractor($extractors, $extractors, $extractors, $extractors); } public function testInstanceOf() { - $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyInfoInterface', $this->propertyInfo); - $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyTypeInfoInterface', $this->propertyInfo); - $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyDescriptionInfoInterface', $this->propertyInfo); - $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyAccessInfoInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface', $this->propertyInfo); + $this->assertInstanceOf('Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface', $this->propertyInfo); } public function testGetShortDescription() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy