123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- <?php
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * 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\DBAL\Types\Type as DBALType;
- use Doctrine\ORM\Mapping\ClassMetadataInfo;
- use Doctrine\ORM\Mapping\MappingException as OrmMappingException;
- use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
- use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
- use Symfony\Component\PropertyInfo\Type;
- /**
- * Extracts data using Doctrine ORM and ODM metadata.
- *
- * @author Kévin Dunglas <dunglas@gmail.com>
- */
- class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeExtractorInterface
- {
- 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;
- } catch (OrmMappingException $exception) {
- return;
- }
- $properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames());
- if ($metadata instanceof ClassMetadataInfo && class_exists('Doctrine\ORM\Mapping\Embedded') && $metadata->embeddedClasses) {
- $properties = array_filter($properties, function ($property) {
- return false === strpos($property, '.');
- });
- $properties = array_merge($properties, array_keys($metadata->embeddedClasses));
- }
- return $properties;
- }
- /**
- * {@inheritdoc}
- */
- public function getTypes($class, $property, array $context = array())
- {
- try {
- $metadata = $this->classMetadataFactory->getMetadataFor($class);
- } catch (MappingException $exception) {
- return;
- } catch (OrmMappingException $exception) {
- return;
- }
- if ($metadata->hasAssociation($property)) {
- $class = $metadata->getAssociationTargetClass($property);
- if ($metadata->isSingleValuedAssociation($property)) {
- if ($metadata instanceof ClassMetadataInfo) {
- $associationMapping = $metadata->getAssociationMapping($property);
- $nullable = $this->isAssociationNullable($associationMapping);
- } else {
- $nullable = false;
- }
- return array(new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $class));
- }
- $collectionKeyType = Type::BUILTIN_TYPE_INT;
- if ($metadata instanceof ClassMetadataInfo) {
- $associationMapping = $metadata->getAssociationMapping($property);
- if (isset($associationMapping['indexBy'])) {
- $indexProperty = $associationMapping['indexBy'];
- /** @var ClassMetadataInfo $subMetadata */
- $subMetadata = $this->classMetadataFactory->getMetadataFor($associationMapping['targetEntity']);
- $typeOfField = $subMetadata->getTypeOfField($indexProperty);
- if (null === $typeOfField) {
- $associationMapping = $subMetadata->getAssociationMapping($indexProperty);
- /** @var ClassMetadataInfo $subMetadata */
- $indexProperty = $subMetadata->getSingleAssociationReferencedJoinColumnName($indexProperty);
- $subMetadata = $this->classMetadataFactory->getMetadataFor($associationMapping['targetEntity']);
- $typeOfField = $subMetadata->getTypeOfField($indexProperty);
- }
- $collectionKeyType = $this->getPhpType($typeOfField);
- }
- }
- return array(new Type(
- Type::BUILTIN_TYPE_OBJECT,
- false,
- 'Doctrine\Common\Collections\Collection',
- true,
- new Type($collectionKeyType),
- new Type(Type::BUILTIN_TYPE_OBJECT, false, $class)
- ));
- }
- if ($metadata instanceof ClassMetadataInfo && class_exists('Doctrine\ORM\Mapping\Embedded') && isset($metadata->embeddedClasses[$property])) {
- return array(new Type(Type::BUILTIN_TYPE_OBJECT, false, $metadata->embeddedClasses[$property]['class']));
- }
- if ($metadata->hasField($property)) {
- $typeOfField = $metadata->getTypeOfField($property);
- $nullable = $metadata instanceof ClassMetadataInfo && $metadata->isNullable($property);
- switch ($typeOfField) {
- case DBALType::DATE:
- case DBALType::DATETIME:
- case DBALType::DATETIMETZ:
- case 'vardatetime':
- case DBALType::TIME:
- return array(new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, 'DateTime'));
- case DBALType::TARRAY:
- return array(new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true));
- case DBALType::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 DBALType::JSON_ARRAY:
- return array(new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true));
- default:
- $builtinType = $this->getPhpType($typeOfField);
- return $builtinType ? array(new Type($builtinType, $nullable)) : null;
- }
- }
- }
- /**
- * Determines whether an association is nullable.
- *
- * @param array $associationMapping
- *
- * @return bool
- *
- * @see https://github.com/doctrine/doctrine2/blob/v2.5.4/lib/Doctrine/ORM/Tools/EntityGenerator.php#L1221-L1246
- */
- private function isAssociationNullable(array $associationMapping)
- {
- if (isset($associationMapping['id']) && $associationMapping['id']) {
- return false;
- }
- if (!isset($associationMapping['joinColumns'])) {
- return true;
- }
- $joinColumns = $associationMapping['joinColumns'];
- foreach ($joinColumns as $joinColumn) {
- if (isset($joinColumn['nullable']) && !$joinColumn['nullable']) {
- return false;
- }
- }
- return true;
- }
- /**
- * Gets the corresponding built-in PHP type.
- *
- * @param string $doctrineType
- *
- * @return string|null
- */
- private function getPhpType($doctrineType)
- {
- switch ($doctrineType) {
- case DBALType::SMALLINT:
- case DBALType::INTEGER:
- return Type::BUILTIN_TYPE_INT;
- case DBALType::FLOAT:
- return Type::BUILTIN_TYPE_FLOAT;
- case DBALType::BIGINT:
- case DBALType::STRING:
- case DBALType::TEXT:
- case DBALType::GUID:
- case DBALType::DECIMAL:
- return Type::BUILTIN_TYPE_STRING;
- case DBALType::BOOLEAN:
- return Type::BUILTIN_TYPE_BOOL;
- case DBALType::BLOB:
- case 'binary':
- return Type::BUILTIN_TYPE_RESOURCE;
- case DBALType::OBJECT:
- return Type::BUILTIN_TYPE_OBJECT;
- }
- }
- }
|