SingleTablePersister.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. /*
  3. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. *
  15. * This software consists of voluntary contributions made by many individuals
  16. * and is licensed under the MIT license. For more information, see
  17. * <http://www.doctrine-project.org>.
  18. */
  19. namespace Doctrine\ORM\Persisters;
  20. use Doctrine\ORM\Mapping\ClassMetadata;
  21. use Doctrine\Common\Collections\Criteria;
  22. /**
  23. * Persister for entities that participate in a hierarchy mapped with the
  24. * SINGLE_TABLE strategy.
  25. *
  26. * @author Roman Borschel <roman@code-factory.org>
  27. * @author Benjamin Eberlei <kontakt@beberlei.de>
  28. * @author Alexander <iam.asm89@gmail.com>
  29. * @since 2.0
  30. * @link http://martinfowler.com/eaaCatalog/singleTableInheritance.html
  31. */
  32. class SingleTablePersister extends AbstractEntityInheritancePersister
  33. {
  34. /**
  35. * {@inheritdoc}
  36. */
  37. protected function getDiscriminatorColumnTableName()
  38. {
  39. return $this->class->getTableName();
  40. }
  41. /**
  42. * {@inheritdoc}
  43. */
  44. protected function getSelectColumnsSQL()
  45. {
  46. if ($this->selectColumnListSql !== null) {
  47. return $this->selectColumnListSql;
  48. }
  49. $columnList[] = parent::getSelectColumnsSQL();
  50. $rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
  51. $tableAlias = $this->getSQLTableAlias($rootClass->name);
  52. // Append discriminator column
  53. $discrColumn = $this->class->discriminatorColumn['name'];
  54. $columnList[] = $tableAlias . '.' . $discrColumn;
  55. $resultColumnName = $this->platform->getSQLResultCasing($discrColumn);
  56. $this->rsm->setDiscriminatorColumn('r', $resultColumnName);
  57. $this->rsm->addMetaResult('r', $resultColumnName, $discrColumn);
  58. // Append subclass columns
  59. foreach ($this->class->subClasses as $subClassName) {
  60. $subClass = $this->em->getClassMetadata($subClassName);
  61. // Regular columns
  62. foreach ($subClass->fieldMappings as $fieldName => $mapping) {
  63. if (isset($mapping['inherited'])) {
  64. continue;
  65. }
  66. $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
  67. }
  68. // Foreign key columns
  69. foreach ($subClass->associationMappings as $assoc) {
  70. if ( ! $assoc['isOwningSide']
  71. || ! ($assoc['type'] & ClassMetadata::TO_ONE)
  72. || isset($assoc['inherited'])) {
  73. continue;
  74. }
  75. foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
  76. $className = isset($assoc['inherited']) ? $assoc['inherited'] : $this->class->name;
  77. $columnList[] = $this->getSelectJoinColumnSQL($tableAlias, $srcColumn, $className);
  78. }
  79. }
  80. }
  81. $this->selectColumnListSql = implode(', ', $columnList);
  82. return $this->selectColumnListSql;
  83. }
  84. /**
  85. * {@inheritdoc}
  86. */
  87. protected function getInsertColumnList()
  88. {
  89. $columns = parent::getInsertColumnList();
  90. // Add discriminator column to the INSERT SQL
  91. $columns[] = $this->class->discriminatorColumn['name'];
  92. return $columns;
  93. }
  94. /**
  95. * {@inheritdoc}
  96. */
  97. protected function getSQLTableAlias($className, $assocName = '')
  98. {
  99. return parent::getSQLTableAlias($this->class->rootEntityName, $assocName);
  100. }
  101. /**
  102. * {@inheritdoc}
  103. */
  104. protected function getSelectConditionSQL(array $criteria, $assoc = null)
  105. {
  106. $conditionSql = parent::getSelectConditionSQL($criteria, $assoc);
  107. if ($conditionSql) {
  108. $conditionSql .= ' AND ';
  109. }
  110. return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL();
  111. }
  112. /**
  113. * {@inheritdoc}
  114. */
  115. protected function getSelectConditionCriteriaSQL(Criteria $criteria)
  116. {
  117. $conditionSql = parent::getSelectConditionCriteriaSQL($criteria);
  118. if ($conditionSql) {
  119. $conditionSql .= ' AND ';
  120. }
  121. return $conditionSql . $this->getSelectConditionDiscriminatorValueSQL();
  122. }
  123. /**
  124. * @return string
  125. */
  126. protected function getSelectConditionDiscriminatorValueSQL()
  127. {
  128. $values = array();
  129. if ($this->class->discriminatorValue !== null) { // discriminators can be 0
  130. $values[] = $this->conn->quote($this->class->discriminatorValue);
  131. }
  132. $discrValues = array_flip($this->class->discriminatorMap);
  133. foreach ($this->class->subClasses as $subclassName) {
  134. $values[] = $this->conn->quote($discrValues[$subclassName]);
  135. }
  136. $values = implode(', ', $values);
  137. $discColumn = $this->class->discriminatorColumn['name'];
  138. $tableAlias = $this->getSQLTableAlias($this->class->name);
  139. return $tableAlias . '.' . $discColumn . ' IN (' . $values . ')';
  140. }
  141. /**
  142. * {@inheritdoc}
  143. */
  144. protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
  145. {
  146. // Ensure that the filters are applied to the root entity of the inheritance tree
  147. $targetEntity = $this->em->getClassMetadata($targetEntity->rootEntityName);
  148. // we don't care about the $targetTableAlias, in a STI there is only one table.
  149. return parent::generateFilterConditionSQL($targetEntity, $targetTableAlias);
  150. }
  151. }