vendor/symfony/doctrine-bridge/Form/DoctrineOrmTypeGuesser.php line 170

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Bridge\Doctrine\Form;
  11. use Doctrine\DBAL\Types\Types;
  12. use Doctrine\ORM\Mapping\ClassMetadataInfo;
  13. use Doctrine\ORM\Mapping\MappingException as LegacyMappingException;
  14. use Doctrine\Persistence\ManagerRegistry;
  15. use Doctrine\Persistence\Mapping\MappingException;
  16. use Doctrine\Persistence\Proxy;
  17. use Symfony\Component\Form\FormTypeGuesserInterface;
  18. use Symfony\Component\Form\Guess\Guess;
  19. use Symfony\Component\Form\Guess\TypeGuess;
  20. use Symfony\Component\Form\Guess\ValueGuess;
  21. class DoctrineOrmTypeGuesser implements FormTypeGuesserInterface
  22. {
  23.     protected $registry;
  24.     private $cache = [];
  25.     public function __construct(ManagerRegistry $registry)
  26.     {
  27.         $this->registry $registry;
  28.     }
  29.     /**
  30.      * {@inheritdoc}
  31.      */
  32.     public function guessType(string $classstring $property)
  33.     {
  34.         if (!$ret $this->getMetadata($class)) {
  35.             return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextType', [], Guess::LOW_CONFIDENCE);
  36.         }
  37.         [$metadata$name] = $ret;
  38.         if ($metadata->hasAssociation($property)) {
  39.             $multiple $metadata->isCollectionValuedAssociation($property);
  40.             $mapping $metadata->getAssociationMapping($property);
  41.             return new TypeGuess('Symfony\Bridge\Doctrine\Form\Type\EntityType', ['em' => $name'class' => $mapping['targetEntity'], 'multiple' => $multiple], Guess::HIGH_CONFIDENCE);
  42.         }
  43.         switch ($metadata->getTypeOfField($property)) {
  44.             case Types::ARRAY:
  45.             case Types::SIMPLE_ARRAY:
  46.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CollectionType', [], Guess::MEDIUM_CONFIDENCE);
  47.             case Types::BOOLEAN:
  48.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CheckboxType', [], Guess::HIGH_CONFIDENCE);
  49.             case Types::DATETIME_MUTABLE:
  50.             case Types::DATETIMETZ_MUTABLE:
  51.             case 'vardatetime':
  52.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateTimeType', [], Guess::HIGH_CONFIDENCE);
  53.             case Types::DATETIME_IMMUTABLE:
  54.             case Types::DATETIMETZ_IMMUTABLE:
  55.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateTimeType', ['input' => 'datetime_immutable'], Guess::HIGH_CONFIDENCE);
  56.             case Types::DATEINTERVAL:
  57.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateIntervalType', [], Guess::HIGH_CONFIDENCE);
  58.             case Types::DATE_MUTABLE:
  59.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', [], Guess::HIGH_CONFIDENCE);
  60.             case Types::DATE_IMMUTABLE:
  61.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', ['input' => 'datetime_immutable'], Guess::HIGH_CONFIDENCE);
  62.             case Types::TIME_MUTABLE:
  63.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TimeType', [], Guess::HIGH_CONFIDENCE);
  64.             case Types::TIME_IMMUTABLE:
  65.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TimeType', ['input' => 'datetime_immutable'], Guess::HIGH_CONFIDENCE);
  66.             case Types::DECIMAL:
  67.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', ['input' => 'string'], Guess::MEDIUM_CONFIDENCE);
  68.             case Types::FLOAT:
  69.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::MEDIUM_CONFIDENCE);
  70.             case Types::INTEGER:
  71.             case Types::BIGINT:
  72.             case Types::SMALLINT:
  73.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\IntegerType', [], Guess::MEDIUM_CONFIDENCE);
  74.             case Types::STRING:
  75.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextType', [], Guess::MEDIUM_CONFIDENCE);
  76.             case Types::TEXT:
  77.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextareaType', [], Guess::MEDIUM_CONFIDENCE);
  78.             default:
  79.                 return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextType', [], Guess::LOW_CONFIDENCE);
  80.         }
  81.     }
  82.     /**
  83.      * {@inheritdoc}
  84.      */
  85.     public function guessRequired(string $classstring $property)
  86.     {
  87.         $classMetadatas $this->getMetadata($class);
  88.         if (!$classMetadatas) {
  89.             return null;
  90.         }
  91.         /** @var ClassMetadataInfo $classMetadata */
  92.         $classMetadata $classMetadatas[0];
  93.         // Check whether the field exists and is nullable or not
  94.         if (isset($classMetadata->fieldMappings[$property])) {
  95.             if (!$classMetadata->isNullable($property) && Types::BOOLEAN !== $classMetadata->getTypeOfField($property)) {
  96.                 return new ValueGuess(trueGuess::HIGH_CONFIDENCE);
  97.             }
  98.             return new ValueGuess(falseGuess::MEDIUM_CONFIDENCE);
  99.         }
  100.         // Check whether the association exists, is a to-one association and its
  101.         // join column is nullable or not
  102.         if ($classMetadata->isAssociationWithSingleJoinColumn($property)) {
  103.             $mapping $classMetadata->getAssociationMapping($property);
  104.             if (!isset($mapping['joinColumns'][0]['nullable'])) {
  105.                 // The "nullable" option defaults to true, in that case the
  106.                 // field should not be required.
  107.                 return new ValueGuess(falseGuess::HIGH_CONFIDENCE);
  108.             }
  109.             return new ValueGuess(!$mapping['joinColumns'][0]['nullable'], Guess::HIGH_CONFIDENCE);
  110.         }
  111.         return null;
  112.     }
  113.     /**
  114.      * {@inheritdoc}
  115.      */
  116.     public function guessMaxLength(string $classstring $property)
  117.     {
  118.         $ret $this->getMetadata($class);
  119.         if ($ret && isset($ret[0]->fieldMappings[$property]) && !$ret[0]->hasAssociation($property)) {
  120.             $mapping $ret[0]->getFieldMapping($property);
  121.             if (isset($mapping['length'])) {
  122.                 return new ValueGuess($mapping['length'], Guess::HIGH_CONFIDENCE);
  123.             }
  124.             if (\in_array($ret[0]->getTypeOfField($property), [Types::DECIMALTypes::FLOAT])) {
  125.                 return new ValueGuess(nullGuess::MEDIUM_CONFIDENCE);
  126.             }
  127.         }
  128.         return null;
  129.     }
  130.     /**
  131.      * {@inheritdoc}
  132.      */
  133.     public function guessPattern(string $classstring $property)
  134.     {
  135.         $ret $this->getMetadata($class);
  136.         if ($ret && isset($ret[0]->fieldMappings[$property]) && !$ret[0]->hasAssociation($property)) {
  137.             if (\in_array($ret[0]->getTypeOfField($property), [Types::DECIMALTypes::FLOAT])) {
  138.                 return new ValueGuess(nullGuess::MEDIUM_CONFIDENCE);
  139.             }
  140.         }
  141.         return null;
  142.     }
  143.     protected function getMetadata(string $class)
  144.     {
  145.         // normalize class name
  146.         $class self::getRealClass(ltrim($class'\\'));
  147.         if (\array_key_exists($class$this->cache)) {
  148.             return $this->cache[$class];
  149.         }
  150.         $this->cache[$class] = null;
  151.         foreach ($this->registry->getManagers() as $name => $em) {
  152.             try {
  153.                 return $this->cache[$class] = [$em->getClassMetadata($class), $name];
  154.             } catch (MappingException $e) {
  155.                 // not an entity or mapped super class
  156.             } catch (LegacyMappingException $e) {
  157.                 // not an entity or mapped super class, using Doctrine ORM 2.2
  158.             }
  159.         }
  160.         return null;
  161.     }
  162.     private static function getRealClass(string $class): string
  163.     {
  164.         if (false === $pos strrpos($class'\\'.Proxy::MARKER.'\\')) {
  165.             return $class;
  166.         }
  167.         return substr($class$pos Proxy::MARKER_LENGTH 2);
  168.     }
  169. }