vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/SingleTablePersister.php line 36

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\ORM\Persisters\Entity;
  4. use Doctrine\Common\Collections\Criteria;
  5. use Doctrine\ORM\Internal\SQLResultCasing;
  6. use Doctrine\ORM\Mapping\ClassMetadata;
  7. use Doctrine\ORM\Utility\PersisterHelper;
  8. use function array_flip;
  9. use function implode;
  10. /**
  11. * Persister for entities that participate in a hierarchy mapped with the
  12. * SINGLE_TABLE strategy.
  13. *
  14. * @link https://martinfowler.com/eaaCatalog/singleTableInheritance.html
  15. */
  16. class SingleTablePersister extends AbstractEntityInheritancePersister
  17. {
  18. use SQLResultCasing;
  19. /**
  20. * {@inheritdoc}
  21. */
  22. protected function getDiscriminatorColumnTableName()
  23. {
  24. return $this->class->getTableName();
  25. }
  26. /**
  27. * {@inheritdoc}
  28. */
  29. protected function getSelectColumnsSQL()
  30. {
  31. if ($this->currentPersisterContext->selectColumnListSql !== null) {
  32. return $this->currentPersisterContext->selectColumnListSql;
  33. }
  34. $columnList[] = parent::getSelectColumnsSQL();
  35. $rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
  36. $tableAlias = $this->getSQLTableAlias($rootClass->name);
  37. // Append discriminator column
  38. $discrColumn = $this->class->getDiscriminatorColumn();
  39. $discrColumnName = $discrColumn['name'];
  40. $discrColumnType = $discrColumn['type'];
  41. $columnList[] = $tableAlias . '.' . $discrColumnName;
  42. $resultColumnName = $this->getSQLResultCasing($this->platform, $discrColumnName);
  43. $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
  44. $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, false, $discrColumnType);
  45. // Append subclass columns
  46. foreach ($this->class->subClasses as $subClassName) {
  47. $subClass = $this->em->getClassMetadata($subClassName);
  48. // Regular columns
  49. foreach ($subClass->fieldMappings as $fieldName => $mapping) {
  50. if (isset($mapping['inherited'])) {
  51. continue;
  52. }
  53. $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
  54. }
  55. // Foreign key columns
  56. foreach ($subClass->associationMappings as $assoc) {
  57. if (! $assoc['isOwningSide'] || ! ($assoc['type'] & ClassMetadata::TO_ONE) || isset($assoc['inherited'])) {
  58. continue;
  59. }
  60. $targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
  61. foreach ($assoc['joinColumns'] as $joinColumn) {
  62. $columnList[] = $this->getSelectJoinColumnSQL(
  63. $tableAlias,
  64. $joinColumn['name'],
  65. $this->quoteStrategy->getJoinColumnName($joinColumn, $subClass, $this->platform),
  66. PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em)
  67. );
  68. }
  69. }
  70. }
  71. $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
  72. return $this->currentPersisterContext->selectColumnListSql;
  73. }
  74. /**
  75. * {@inheritdoc}
  76. */
  77. protected function getInsertColumnList()
  78. {
  79. $columns = parent::getInsertColumnList();
  80. // Add discriminator column to the INSERT SQL
  81. $columns[] = $this->class->getDiscriminatorColumn()['name'];
  82. return $columns;
  83. }
  84. /**
  85. * {@inheritdoc}
  86. */
  87. protected function getSQLTableAlias($className, $assocName = '')
  88. {
  89. return parent::getSQLTableAlias($this->class->rootEntityName, $assocName);
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. protected function getSelectConditionSQL(array $criteria, $assoc = null)
  95. {
  96. $conditionSql = parent::getSelectConditionSQL($criteria, $assoc);
  97. if ($conditionSql) {
  98. $conditionSql .= ' AND ';
  99. }
  100. return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL();
  101. }
  102. /**
  103. * {@inheritdoc}
  104. */
  105. protected function getSelectConditionCriteriaSQL(Criteria $criteria)
  106. {
  107. $conditionSql = parent::getSelectConditionCriteriaSQL($criteria);
  108. if ($conditionSql) {
  109. $conditionSql .= ' AND ';
  110. }
  111. return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL();
  112. }
  113. /** @return string */
  114. protected function getSelectConditionDiscriminatorValueSQL()
  115. {
  116. $values = [];
  117. if ($this->class->discriminatorValue !== null) { // discriminators can be 0
  118. $values[] = $this->conn->quote($this->class->discriminatorValue);
  119. }
  120. $discrValues = array_flip($this->class->discriminatorMap);
  121. foreach ($this->class->subClasses as $subclassName) {
  122. $values[] = $this->conn->quote($discrValues[$subclassName]);
  123. }
  124. $discColumnName = $this->class->getDiscriminatorColumn()['name'];
  125. $values = implode(', ', $values);
  126. $tableAlias = $this->getSQLTableAlias($this->class->name);
  127. return $tableAlias . '.' . $discColumnName . ' IN (' . $values . ')';
  128. }
  129. /**
  130. * {@inheritdoc}
  131. */
  132. protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
  133. {
  134. // Ensure that the filters are applied to the root entity of the inheritance tree
  135. $targetEntity = $this->em->getClassMetadata($targetEntity->rootEntityName);
  136. // we don't care about the $targetTableAlias, in a STI there is only one table.
  137. return parent::generateFilterConditionSQL($targetEntity, $targetTableAlias);
  138. }
  139. }