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

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. }