Rajout de doctrine/orm
[zf2.biz/galerie.git] / vendor / doctrine / orm / lib / Doctrine / ORM / Query / Exec / MultiTableDeleteExecutor.php
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
20 namespace Doctrine\ORM\Query\Exec;
21
22 use Doctrine\DBAL\Connection,
23     Doctrine\ORM\Query\AST;
24
25 /**
26  * Executes the SQL statements for bulk DQL DELETE statements on classes in
27  * Class Table Inheritance (JOINED).
28  *
29  * @author      Roman Borschel <roman@code-factory.org>
30  * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
31  * @link        http://www.doctrine-project.org
32  * @since       2.0
33  */
34 class MultiTableDeleteExecutor extends AbstractSqlExecutor
35 {
36     private $_createTempTableSql;
37     private $_dropTempTableSql;
38     private $_insertSql;
39
40     /**
41      * Initializes a new <tt>MultiTableDeleteExecutor</tt>.
42      *
43      * @param Node $AST The root AST node of the DQL query.
44      * @param SqlWalker $sqlWalker The walker used for SQL generation from the AST.
45      * @internal Any SQL construction and preparation takes place in the constructor for
46      *           best performance. With a query cache the executor will be cached.
47      */
48     public function __construct(AST\Node $AST, $sqlWalker)
49     {
50         $em             = $sqlWalker->getEntityManager();
51         $conn           = $em->getConnection();
52         $platform       = $conn->getDatabasePlatform();
53         $quoteStrategy  = $em->getConfiguration()->getQuoteStrategy();
54
55         $primaryClass       = $em->getClassMetadata($AST->deleteClause->abstractSchemaName);
56         $primaryDqlAlias    = $AST->deleteClause->aliasIdentificationVariable;
57         $rootClass          = $em->getClassMetadata($primaryClass->rootEntityName);
58
59         $tempTable      = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName());
60         $idColumnNames  = $rootClass->getIdentifierColumnNames();
61         $idColumnList   = implode(', ', $idColumnNames);
62
63         // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause()
64         $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $primaryDqlAlias);
65
66         $this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')'
67                 . ' SELECT t0.' . implode(', t0.', $idColumnNames);
68
69         $rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $primaryDqlAlias);
70         $fromClause = new AST\FromClause(array(new AST\IdentificationVariableDeclaration($rangeDecl, null, array())));
71         $this->_insertSql .= $sqlWalker->walkFromClause($fromClause);
72
73         // Append WHERE clause, if there is one.
74         if ($AST->whereClause) {
75             $this->_insertSql .= $sqlWalker->walkWhereClause($AST->whereClause);
76         }
77
78         // 2. Create ID subselect statement used in DELETE ... WHERE ... IN (subselect)
79         $idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable;
80
81         // 3. Create and store DELETE statements
82         $classNames = array_merge($primaryClass->parentClasses, array($primaryClass->name), $primaryClass->subClasses);
83         foreach (array_reverse($classNames) as $className) {
84             $tableName = $quoteStrategy->getTableName($em->getClassMetadata($className), $platform);
85             $this->_sqlStatements[] = 'DELETE FROM ' . $tableName
86                     . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')';
87         }
88
89         // 4. Store DDL for temporary identifier table.
90         $columnDefinitions = array();
91         foreach ($idColumnNames as $idColumnName) {
92             $columnDefinitions[$idColumnName] = array(
93                 'notnull' => true,
94                 'type' => \Doctrine\DBAL\Types\Type::getType($rootClass->getTypeOfColumn($idColumnName))
95             );
96         }
97         $this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' ('
98                 . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')';
99         $this->_dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable);
100     }
101
102     /**
103      * {@inheritDoc}
104      */
105     public function execute(Connection $conn, array $params, array $types)
106     {
107         $numDeleted = 0;
108
109         // Create temporary id table
110         $conn->executeUpdate($this->_createTempTableSql);
111
112         try {
113             // Insert identifiers
114             $numDeleted = $conn->executeUpdate($this->_insertSql, $params, $types);
115
116             // Execute DELETE statements
117             foreach ($this->_sqlStatements as $sql) {
118                 $conn->executeUpdate($sql);
119             }
120         } catch (\Exception $exception) {
121             // FAILURE! Drop temporary table to avoid possible collisions
122             $conn->executeUpdate($this->_dropTempTableSql);
123
124             // Re-throw exception
125             throw $exception;
126         }
127
128         // Drop temporary table
129         $conn->executeUpdate($this->_dropTempTableSql);
130
131         return $numDeleted;
132     }
133 }