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

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