PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php

https://github.com/maartendekeizer/doctrine2
PHP | 310 lines | 175 code | 45 blank | 90 comment | 27 complexity | 5a93308dadd740c7d6a8f383fa57b83b MD5 | raw file
  1. <?php
  2. /*
  3. * $Id$
  4. *
  5. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  6. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  7. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  8. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  9. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  10. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  11. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  13. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  14. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  15. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. *
  17. * This software consists of voluntary contributions made by many individuals
  18. * and is licensed under the LGPL. For more information, see
  19. * <http://www.doctrine-project.org>.
  20. */
  21. namespace Doctrine\ORM\Persisters;
  22. use Doctrine\ORM\PersistentCollection,
  23. Doctrine\ORM\UnitOfWork;
  24. /**
  25. * Persister for many-to-many collections.
  26. *
  27. * @author Roman Borschel <roman@code-factory.org>
  28. * @since 2.0
  29. */
  30. class ManyToManyPersister extends AbstractCollectionPersister
  31. {
  32. /**
  33. * {@inheritdoc}
  34. *
  35. * @override
  36. */
  37. protected function _getDeleteRowSQL(PersistentCollection $coll)
  38. {
  39. $mapping = $coll->getMapping();
  40. $class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
  41. return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
  42. . ' WHERE ' . implode(' = ? AND ', $mapping['joinTableColumns']) . ' = ?';
  43. }
  44. /**
  45. * {@inheritdoc}
  46. *
  47. * @override
  48. * @internal Order of the parameters must be the same as the order of the columns in
  49. * _getDeleteRowSql.
  50. */
  51. protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element)
  52. {
  53. return $this->_collectJoinTableColumnParameters($coll, $element);
  54. }
  55. /**
  56. * {@inheritdoc}
  57. *
  58. * @override
  59. */
  60. protected function _getUpdateRowSQL(PersistentCollection $coll)
  61. {}
  62. /**
  63. * {@inheritdoc}
  64. *
  65. * @override
  66. * @internal Order of the parameters must be the same as the order of the columns in
  67. * _getInsertRowSql.
  68. */
  69. protected function _getInsertRowSQL(PersistentCollection $coll)
  70. {
  71. $mapping = $coll->getMapping();
  72. $columns = $mapping['joinTableColumns'];
  73. $class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
  74. return 'INSERT INTO ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
  75. . ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
  76. }
  77. /**
  78. * {@inheritdoc}
  79. *
  80. * @override
  81. * @internal Order of the parameters must be the same as the order of the columns in
  82. * _getInsertRowSql.
  83. */
  84. protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element)
  85. {
  86. return $this->_collectJoinTableColumnParameters($coll, $element);
  87. }
  88. /**
  89. * Collects the parameters for inserting/deleting on the join table in the order
  90. * of the join table columns as specified in ManyToManyMapping#joinTableColumns.
  91. *
  92. * @param $coll
  93. * @param $element
  94. * @return array
  95. */
  96. private function _collectJoinTableColumnParameters(PersistentCollection $coll, $element)
  97. {
  98. $params = array();
  99. $mapping = $coll->getMapping();
  100. $isComposite = count($mapping['joinTableColumns']) > 2;
  101. $identifier1 = $this->_uow->getEntityIdentifier($coll->getOwner());
  102. $identifier2 = $this->_uow->getEntityIdentifier($element);
  103. if ($isComposite) {
  104. $class1 = $this->_em->getClassMetadata(get_class($coll->getOwner()));
  105. $class2 = $coll->getTypeClass();
  106. }
  107. foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
  108. if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
  109. if ($isComposite) {
  110. if ($class1->containsForeignIdentifier) {
  111. $params[] = $identifier1[$class1->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
  112. } else {
  113. $params[] = $identifier1[$class1->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
  114. }
  115. } else {
  116. $params[] = array_pop($identifier1);
  117. }
  118. } else {
  119. if ($isComposite) {
  120. if ($class2->containsForeignIdentifier) {
  121. $params[] = $identifier2[$class2->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
  122. } else {
  123. $params[] = $identifier2[$class2->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
  124. }
  125. } else {
  126. $params[] = array_pop($identifier2);
  127. }
  128. }
  129. }
  130. return $params;
  131. }
  132. /**
  133. * {@inheritdoc}
  134. *
  135. * @override
  136. */
  137. protected function _getDeleteSQL(PersistentCollection $coll)
  138. {
  139. $mapping = $coll->getMapping();
  140. $class = $this->_em->getClassMetadata(get_class($coll->getOwner()));
  141. $joinTable = $mapping['joinTable'];
  142. $whereClause = '';
  143. foreach ($mapping['relationToSourceKeyColumns'] as $relationColumn => $srcColumn) {
  144. if ($whereClause !== '') $whereClause .= ' AND ';
  145. $whereClause .= $relationColumn . ' = ?';
  146. }
  147. return 'DELETE FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
  148. . ' WHERE ' . $whereClause;
  149. }
  150. /**
  151. * {@inheritdoc}
  152. *
  153. * @override
  154. * @internal Order of the parameters must be the same as the order of the columns in
  155. * _getDeleteSql.
  156. */
  157. protected function _getDeleteSQLParameters(PersistentCollection $coll)
  158. {
  159. $params = array();
  160. $mapping = $coll->getMapping();
  161. $identifier = $this->_uow->getEntityIdentifier($coll->getOwner());
  162. if (count($mapping['relationToSourceKeyColumns']) > 1) {
  163. $sourceClass = $this->_em->getClassMetadata(get_class($mapping->getOwner()));
  164. foreach ($mapping['relationToSourceKeyColumns'] as $relColumn => $srcColumn) {
  165. $params[] = $identifier[$sourceClass->fieldNames[$srcColumn]];
  166. }
  167. } else {
  168. $params[] = array_pop($identifier);
  169. }
  170. return $params;
  171. }
  172. /**
  173. * {@inheritdoc}
  174. */
  175. public function count(PersistentCollection $coll)
  176. {
  177. $params = array();
  178. $mapping = $coll->getMapping();
  179. $class = $this->_em->getClassMetadata($mapping['sourceEntity']);
  180. $id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
  181. if ($mapping['isOwningSide']) {
  182. $joinColumns = $mapping['relationToSourceKeyColumns'];
  183. } else {
  184. $mapping = $this->_em->getClassMetadata($mapping['targetEntity'])->associationMappings[$mapping['mappedBy']];
  185. $joinColumns = $mapping['relationToTargetKeyColumns'];
  186. }
  187. $whereClause = '';
  188. foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
  189. if (isset($joinColumns[$joinTableColumn])) {
  190. if ($whereClause !== '') {
  191. $whereClause .= ' AND ';
  192. }
  193. $whereClause .= "$joinTableColumn = ?";
  194. $params[] = ($class->containsForeignIdentifier)
  195. ? $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])]
  196. : $id[$class->fieldNames[$joinColumns[$joinTableColumn]]];
  197. }
  198. }
  199. $sql = 'SELECT COUNT(*)'
  200. . ' FROM ' . $class->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
  201. . ' WHERE ' . $whereClause;
  202. return $this->_conn->fetchColumn($sql, $params);
  203. }
  204. /**
  205. * @param PersistentCollection $coll
  206. * @param int $offset
  207. * @param int $length
  208. * @return array
  209. */
  210. public function slice(PersistentCollection $coll, $offset, $length = null)
  211. {
  212. $mapping = $coll->getMapping();
  213. return $this->_em->getUnitOfWork()->getEntityPersister($mapping['targetEntity'])->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length);
  214. }
  215. /**
  216. * @param PersistentCollection $coll
  217. * @param object $element
  218. */
  219. public function contains(PersistentCollection $coll, $element)
  220. {
  221. $uow = $this->_em->getUnitOfWork();
  222. // shortcut for new entities
  223. if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
  224. return false;
  225. }
  226. $params = array();
  227. $mapping = $coll->getMapping();
  228. if ( ! $mapping['isOwningSide']) {
  229. $sourceClass = $this->_em->getClassMetadata($mapping['targetEntity']);
  230. $targetClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
  231. $sourceId = $uow->getEntityIdentifier($element);
  232. $targetId = $uow->getEntityIdentifier($coll->getOwner());
  233. $mapping = $sourceClass->associationMappings[$mapping['mappedBy']];
  234. } else {
  235. $sourceClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
  236. $targetClass = $this->_em->getClassMetadata($mapping['targetEntity']);
  237. $sourceId = $uow->getEntityIdentifier($coll->getOwner());
  238. $targetId = $uow->getEntityIdentifier($element);
  239. }
  240. $whereClause = '';
  241. foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
  242. if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) {
  243. if ($whereClause !== '') {
  244. $whereClause .= ' AND ';
  245. }
  246. $whereClause .= $joinTableColumn . ' = ?';
  247. $params[] = ($targetClass->containsForeignIdentifier)
  248. ? $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])]
  249. : $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
  250. } else if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
  251. if ($whereClause !== '') {
  252. $whereClause .= ' AND ';
  253. }
  254. $whereClause .= $joinTableColumn . ' = ?';
  255. $params[] = ($sourceClass->containsForeignIdentifier)
  256. ? $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])]
  257. : $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
  258. }
  259. }
  260. $sql = 'SELECT 1'
  261. . ' FROM ' . $sourceClass->getQuotedJoinTableName($mapping, $this->_conn->getDatabasePlatform())
  262. . ' WHERE ' . $whereClause;
  263. return (bool) $this->_conn->fetchColumn($sql, $params);
  264. }
  265. }