vendor/doctrine/lib/Doctrine/ORM/Persisters/ManyToManyPersister.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     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 
       
    22 namespace Doctrine\ORM\Persisters;
       
    23 
       
    24 use Doctrine\ORM\PersistentCollection,
       
    25     Doctrine\ORM\UnitOfWork;
       
    26 
       
    27 /**
       
    28  * Persister for many-to-many collections.
       
    29  *
       
    30  * @author Roman Borschel <roman@code-factory.org>
       
    31  * @since 2.0
       
    32  */
       
    33 class ManyToManyPersister extends AbstractCollectionPersister
       
    34 {
       
    35     /**
       
    36      * {@inheritdoc}
       
    37      *
       
    38      * @override
       
    39      */
       
    40     protected function _getDeleteRowSQL(PersistentCollection $coll)
       
    41     {
       
    42         $mapping = $coll->getMapping();
       
    43         $joinTable = $mapping['joinTable'];
       
    44         $columns = $mapping['joinTableColumns'];
       
    45         return 'DELETE FROM ' . $joinTable['name'] . ' WHERE ' . implode(' = ? AND ', $columns) . ' = ?';
       
    46     }
       
    47 
       
    48     /**
       
    49      * {@inheritdoc}
       
    50      *
       
    51      * @override
       
    52      * @internal Order of the parameters must be the same as the order of the columns in
       
    53      *           _getDeleteRowSql.
       
    54      */
       
    55     protected function _getDeleteRowSQLParameters(PersistentCollection $coll, $element)
       
    56     {
       
    57         return $this->_collectJoinTableColumnParameters($coll, $element);
       
    58     }
       
    59 
       
    60     /**
       
    61      * {@inheritdoc}
       
    62      *
       
    63      * @override
       
    64      */
       
    65     protected function _getUpdateRowSQL(PersistentCollection $coll)
       
    66     {}
       
    67 
       
    68     /**
       
    69      * {@inheritdoc}
       
    70      *
       
    71      * @override
       
    72      * @internal Order of the parameters must be the same as the order of the columns in
       
    73      *           _getInsertRowSql.
       
    74      */
       
    75     protected function _getInsertRowSQL(PersistentCollection $coll)
       
    76     {
       
    77         $mapping = $coll->getMapping();
       
    78         $joinTable = $mapping['joinTable'];
       
    79         $columns = $mapping['joinTableColumns'];
       
    80         return 'INSERT INTO ' . $joinTable['name'] . ' (' . implode(', ', $columns) . ')'
       
    81                 . ' VALUES (' . implode(', ', array_fill(0, count($columns), '?')) . ')';
       
    82     }
       
    83 
       
    84     /**
       
    85      * {@inheritdoc}
       
    86      *
       
    87      * @override
       
    88      * @internal Order of the parameters must be the same as the order of the columns in
       
    89      *           _getInsertRowSql.
       
    90      */
       
    91     protected function _getInsertRowSQLParameters(PersistentCollection $coll, $element)
       
    92     {
       
    93         return $this->_collectJoinTableColumnParameters($coll, $element);
       
    94     }
       
    95 
       
    96     /**
       
    97      * Collects the parameters for inserting/deleting on the join table in the order
       
    98      * of the join table columns as specified in ManyToManyMapping#joinTableColumns.
       
    99      *
       
   100      * @param $coll
       
   101      * @param $element
       
   102      * @return array
       
   103      */
       
   104     private function _collectJoinTableColumnParameters(PersistentCollection $coll, $element)
       
   105     {
       
   106         $params = array();
       
   107         $mapping = $coll->getMapping();
       
   108         $isComposite = count($mapping['joinTableColumns']) > 2;
       
   109 
       
   110         $identifier1 = $this->_uow->getEntityIdentifier($coll->getOwner());
       
   111         $identifier2 = $this->_uow->getEntityIdentifier($element);
       
   112 
       
   113         if ($isComposite) {
       
   114             $class1 = $this->_em->getClassMetadata(get_class($coll->getOwner()));
       
   115             $class2 = $coll->getTypeClass();
       
   116         }
       
   117 
       
   118         foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
       
   119             if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
       
   120                 if ($isComposite) {
       
   121                     if ($class1->containsForeignIdentifier) {
       
   122                         $params[] = $identifier1[$class1->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
       
   123                     } else {
       
   124                         $params[] = $identifier1[$class1->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
       
   125                     }
       
   126                 } else {
       
   127                     $params[] = array_pop($identifier1);
       
   128                 }
       
   129             } else {
       
   130                 if ($isComposite) {
       
   131                     if ($class2->containsForeignIdentifier) {
       
   132                         $params[] = $identifier2[$class2->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
       
   133                     } else {
       
   134                         $params[] = $identifier2[$class2->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
       
   135                     }
       
   136                 } else {
       
   137                     $params[] = array_pop($identifier2);
       
   138                 }
       
   139             }
       
   140         }
       
   141 
       
   142         return $params;
       
   143     }
       
   144 
       
   145     /**
       
   146      * {@inheritdoc}
       
   147      *
       
   148      * @override
       
   149      */
       
   150     protected function _getDeleteSQL(PersistentCollection $coll)
       
   151     {
       
   152         $mapping = $coll->getMapping();
       
   153         $joinTable = $mapping['joinTable'];
       
   154         $whereClause = '';
       
   155         foreach ($mapping['relationToSourceKeyColumns'] as $relationColumn => $srcColumn) {
       
   156             if ($whereClause !== '') $whereClause .= ' AND ';
       
   157             $whereClause .= "$relationColumn = ?";
       
   158         }
       
   159         return 'DELETE FROM ' . $joinTable['name'] . ' WHERE ' . $whereClause;
       
   160     }
       
   161 
       
   162     /**
       
   163      * {@inheritdoc}
       
   164      *
       
   165      * @override
       
   166      * @internal Order of the parameters must be the same as the order of the columns in
       
   167      *           _getDeleteSql.
       
   168      */
       
   169     protected function _getDeleteSQLParameters(PersistentCollection $coll)
       
   170     {
       
   171         $params = array();
       
   172         $mapping = $coll->getMapping();
       
   173         $identifier = $this->_uow->getEntityIdentifier($coll->getOwner());
       
   174         if (count($mapping['relationToSourceKeyColumns']) > 1) {
       
   175             $sourceClass = $this->_em->getClassMetadata(get_class($mapping->getOwner()));
       
   176             foreach ($mapping['relationToSourceKeyColumns'] as $relColumn => $srcColumn) {
       
   177                 $params[] = $identifier[$sourceClass->fieldNames[$srcColumn]];
       
   178             }
       
   179         } else {
       
   180            $params[] = array_pop($identifier);
       
   181         }
       
   182 
       
   183         return $params;
       
   184     }
       
   185 
       
   186     /**
       
   187      * {@inheritdoc}
       
   188      */
       
   189     public function count(PersistentCollection $coll)
       
   190     {
       
   191         $params = array();
       
   192         $mapping = $coll->getMapping();
       
   193         $class = $this->_em->getClassMetadata($mapping['sourceEntity']);
       
   194         $id = $this->_em->getUnitOfWork()->getEntityIdentifier($coll->getOwner());
       
   195 
       
   196         if ($mapping['isOwningSide']) {
       
   197             $joinTable = $mapping['joinTable'];
       
   198             $joinColumns = $mapping['relationToSourceKeyColumns'];
       
   199         } else {
       
   200             $mapping = $this->_em->getClassMetadata($mapping['targetEntity'])->associationMappings[$mapping['mappedBy']];
       
   201             $joinTable = $mapping['joinTable'];
       
   202             $joinColumns = $mapping['relationToTargetKeyColumns'];
       
   203         }
       
   204 
       
   205         $whereClause = '';
       
   206         foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
       
   207             if (isset($joinColumns[$joinTableColumn])) {
       
   208                 if ($whereClause !== '') {
       
   209                     $whereClause .= ' AND ';
       
   210                 }
       
   211                 $whereClause .= "$joinTableColumn = ?";
       
   212 
       
   213                 if ($class->containsForeignIdentifier) {
       
   214                     $params[] = $id[$class->getFieldForColumn($joinColumns[$joinTableColumn])];
       
   215                 } else {
       
   216                     $params[] = $id[$class->fieldNames[$joinColumns[$joinTableColumn]]];
       
   217                 }
       
   218             }
       
   219         }
       
   220         $sql = 'SELECT count(*) FROM ' . $joinTable['name'] . ' WHERE ' . $whereClause;
       
   221 
       
   222         return $this->_conn->fetchColumn($sql, $params);
       
   223     }
       
   224 
       
   225     /**
       
   226      * @param PersistentCollection $coll
       
   227      * @param int $offset
       
   228      * @param int $length
       
   229      * @return array
       
   230      */
       
   231     public function slice(PersistentCollection $coll, $offset, $length = null)
       
   232     {
       
   233         $mapping = $coll->getMapping();
       
   234         return $this->_em->getUnitOfWork()
       
   235                   ->getEntityPersister($mapping['targetEntity'])
       
   236                   ->getManyToManyCollection($mapping, $coll->getOwner(), $offset, $length);
       
   237     }
       
   238 
       
   239     /**
       
   240      * @param PersistentCollection $coll
       
   241      * @param object $element
       
   242      */
       
   243     public function contains(PersistentCollection $coll, $element)
       
   244     {
       
   245         $uow = $this->_em->getUnitOfWork();
       
   246 
       
   247         // shortcut for new entities
       
   248         if ($uow->getEntityState($element, UnitOfWork::STATE_NEW) == UnitOfWork::STATE_NEW) {
       
   249             return false;
       
   250         }
       
   251 
       
   252         $params = array();
       
   253         $mapping = $coll->getMapping();
       
   254 
       
   255         if (!$mapping['isOwningSide']) {
       
   256             $sourceClass = $this->_em->getClassMetadata($mapping['targetEntity']);
       
   257             $targetClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
       
   258             $sourceId = $uow->getEntityIdentifier($element);
       
   259             $targetId = $uow->getEntityIdentifier($coll->getOwner());
       
   260             
       
   261             $mapping = $sourceClass->associationMappings[$mapping['mappedBy']];
       
   262         } else {
       
   263             $sourceClass = $this->_em->getClassMetadata($mapping['sourceEntity']);
       
   264             $targetClass = $this->_em->getClassMetadata($mapping['targetEntity']);
       
   265             $sourceId = $uow->getEntityIdentifier($coll->getOwner());
       
   266             $targetId = $uow->getEntityIdentifier($element);
       
   267         }
       
   268         $joinTable = $mapping['joinTable'];
       
   269 
       
   270         $whereClause = '';
       
   271         foreach ($mapping['joinTableColumns'] as $joinTableColumn) {
       
   272             if (isset($mapping['relationToTargetKeyColumns'][$joinTableColumn])) {
       
   273                 if ($whereClause !== '') {
       
   274                     $whereClause .= ' AND ';
       
   275                 }
       
   276                 $whereClause .= "$joinTableColumn = ?";
       
   277 
       
   278                 if ($targetClass->containsForeignIdentifier) {
       
   279                     $params[] = $targetId[$targetClass->getFieldForColumn($mapping['relationToTargetKeyColumns'][$joinTableColumn])];
       
   280                 } else {
       
   281                     $params[] = $targetId[$targetClass->fieldNames[$mapping['relationToTargetKeyColumns'][$joinTableColumn]]];
       
   282                 }
       
   283             } else if (isset($mapping['relationToSourceKeyColumns'][$joinTableColumn])) {
       
   284                 if ($whereClause !== '') {
       
   285                     $whereClause .= ' AND ';
       
   286                 }
       
   287                 $whereClause .= "$joinTableColumn = ?";
       
   288 
       
   289                 if ($sourceClass->containsForeignIdentifier) {
       
   290                     $params[] = $sourceId[$sourceClass->getFieldForColumn($mapping['relationToSourceKeyColumns'][$joinTableColumn])];
       
   291                 } else {
       
   292                     $params[] = $sourceId[$sourceClass->fieldNames[$mapping['relationToSourceKeyColumns'][$joinTableColumn]]];
       
   293                 }
       
   294             }
       
   295         }
       
   296         $sql = 'SELECT 1 FROM ' . $joinTable['name'] . ' WHERE ' . $whereClause;
       
   297 
       
   298         return (bool)$this->_conn->fetchColumn($sql, $params);
       
   299     }
       
   300 }