vendor/doctrine/orm/src/Internal/Hydration/SimpleObjectHydrator.php line 66

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\ORM\Internal\Hydration;
  4. use Doctrine\ORM\Internal\SQLResultCasing;
  5. use Doctrine\ORM\Mapping\ClassMetadata;
  6. use Doctrine\ORM\Mapping\MappingException;
  7. use Doctrine\ORM\Query;
  8. use Exception;
  9. use RuntimeException;
  10. use ValueError;
  11. use function array_keys;
  12. use function array_search;
  13. use function count;
  14. use function in_array;
  15. use function is_array;
  16. use function key;
  17. use function reset;
  18. use function sprintf;
  19. class SimpleObjectHydrator extends AbstractHydrator
  20. {
  21.     use SQLResultCasing;
  22.     /** @var ClassMetadata */
  23.     private $class;
  24.     /**
  25.      * {@inheritDoc}
  26.      */
  27.     protected function prepare()
  28.     {
  29.         if (count($this->resultSetMapping()->aliasMap) !== 1) {
  30.             throw new RuntimeException('Cannot use SimpleObjectHydrator with a ResultSetMapping that contains more than one object result.');
  31.         }
  32.         if ($this->resultSetMapping()->scalarMappings) {
  33.             throw new RuntimeException('Cannot use SimpleObjectHydrator with a ResultSetMapping that contains scalar mappings.');
  34.         }
  35.         $this->class = $this->getClassMetadata(reset($this->resultSetMapping()->aliasMap));
  36.     }
  37.     /**
  38.      * {@inheritDoc}
  39.      */
  40.     protected function cleanup()
  41.     {
  42.         parent::cleanup();
  43.         $this->_uow->triggerEagerLoads();
  44.         $this->_uow->hydrationComplete();
  45.     }
  46.     /**
  47.      * {@inheritDoc}
  48.      */
  49.     protected function hydrateAllData()
  50.     {
  51.         $result = [];
  52.         while ($row = $this->statement()->fetchAssociative()) {
  53.             $this->hydrateRowData($row, $result);
  54.         }
  55.         $this->_em->getUnitOfWork()->triggerEagerLoads();
  56.         return $result;
  57.     }
  58.     /**
  59.      * {@inheritDoc}
  60.      */
  61.     protected function hydrateRowData(array $row, array &$result)
  62.     {
  63.         $entityName       = $this->class->name;
  64.         $data             = [];
  65.         $discrColumnValue = null;
  66.         // We need to find the correct entity class name if we have inheritance in resultset
  67.         if ($this->class->inheritanceType !== ClassMetadata::INHERITANCE_TYPE_NONE) {
  68.             $discrColumn     = $this->class->getDiscriminatorColumn();
  69.             $discrColumnName = $this->getSQLResultCasing($this->_platform, $discrColumn['name']);
  70.             // Find mapped discriminator column from the result set.
  71.             $metaMappingDiscrColumnName = array_search($discrColumnName, $this->resultSetMapping()->metaMappings, true);
  72.             if ($metaMappingDiscrColumnName) {
  73.                 $discrColumnName = $metaMappingDiscrColumnName;
  74.             }
  75.             if (! isset($row[$discrColumnName])) {
  76.                 throw HydrationException::missingDiscriminatorColumn(
  77.                     $entityName,
  78.                     $discrColumnName,
  79.                     key($this->resultSetMapping()->aliasMap)
  80.                 );
  81.             }
  82.             if ($row[$discrColumnName] === '') {
  83.                 throw HydrationException::emptyDiscriminatorValue(key(
  84.                     $this->resultSetMapping()->aliasMap
  85.                 ));
  86.             }
  87.             $discrMap = $this->class->discriminatorMap;
  88.             if (! isset($discrMap[$row[$discrColumnName]])) {
  89.                 throw HydrationException::invalidDiscriminatorValue($row[$discrColumnName], array_keys($discrMap));
  90.             }
  91.             $entityName       = $discrMap[$row[$discrColumnName]];
  92.             $discrColumnValue = $row[$discrColumnName];
  93.             unset($row[$discrColumnName]);
  94.         }
  95.         foreach ($row as $column => $value) {
  96.             // An ObjectHydrator should be used instead of SimpleObjectHydrator
  97.             if (isset($this->resultSetMapping()->relationMap[$column])) {
  98.                 throw new Exception(sprintf('Unable to retrieve association information for column "%s"', $column));
  99.             }
  100.             $cacheKeyInfo = $this->hydrateColumnInfo($column);
  101.             if (! $cacheKeyInfo) {
  102.                 continue;
  103.             }
  104.             // If we have inheritance in resultset, make sure the field belongs to the correct class
  105.             if (isset($cacheKeyInfo['discriminatorValues']) && ! in_array((string) $discrColumnValue, $cacheKeyInfo['discriminatorValues'], true)) {
  106.                 continue;
  107.             }
  108.             // Check if value is null before conversion (because some types convert null to something else)
  109.             $valueIsNull = $value === null;
  110.             // Convert field to a valid PHP value
  111.             if (isset($cacheKeyInfo['type'])) {
  112.                 $type  = $cacheKeyInfo['type'];
  113.                 $value = $type->convertToPHPValue($value, $this->_platform);
  114.             }
  115.             if ($value !== null && isset($cacheKeyInfo['enumType'])) {
  116.                 $originalValue = $currentValue = $value;
  117.                 try {
  118.                     if (! is_array($originalValue)) {
  119.                         $value = $this->buildEnum($originalValue, $cacheKeyInfo['enumType']);
  120.                     } else {
  121.                         $value = [];
  122.                         foreach ($originalValue as $i => $currentValue) {
  123.                             $value[$i] = $this->buildEnum($currentValue, $cacheKeyInfo['enumType']);
  124.                         }
  125.                     }
  126.                 } catch (ValueError $e) {
  127.                     throw MappingException::invalidEnumValue(
  128.                         $entityName,
  129.                         $cacheKeyInfo['fieldName'],
  130.                         (string) $currentValue,
  131.                         $cacheKeyInfo['enumType'],
  132.                         $e
  133.                     );
  134.                 }
  135.             }
  136.             $fieldName = $cacheKeyInfo['fieldName'];
  137.             // Prevent overwrite in case of inherit classes using same property name (See AbstractHydrator)
  138.             if (! isset($data[$fieldName]) || ! $valueIsNull) {
  139.                 $data[$fieldName] = $value;
  140.             }
  141.         }
  142.         if (isset($this->_hints[Query::HINT_REFRESH_ENTITY])) {
  143.             $this->registerManaged($this->class, $this->_hints[Query::HINT_REFRESH_ENTITY], $data);
  144.         }
  145.         $uow    = $this->_em->getUnitOfWork();
  146.         $entity = $uow->createEntity($entityName, $data, $this->_hints);
  147.         $result[] = $entity;
  148.         if (isset($this->_hints[Query::HINT_INTERNAL_ITERATION]) && $this->_hints[Query::HINT_INTERNAL_ITERATION]) {
  149.             $this->_uow->hydrationComplete();
  150.         }
  151.     }
  152. }