These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 | use Doctrine\DBAL\Types\Type; |
||
24 | use Doctrine\ORM\Query\AST; |
||
25 | use Doctrine\ORM\Utility\PersisterHelper; |
||
26 | |||
27 | /** |
||
28 | * Executes the SQL statements for bulk DQL DELETE statements on classes in |
||
29 | * Class Table Inheritance (JOINED). |
||
30 | * |
||
31 | * @author Roman Borschel <[email protected]> |
||
32 | * @license http://www.opensource.org/licenses/mit-license.php MIT |
||
33 | * @link http://www.doctrine-project.org |
||
34 | * @since 2.0 |
||
35 | */ |
||
36 | class MultiTableDeleteExecutor extends AbstractSqlExecutor |
||
37 | { |
||
38 | /** |
||
39 | * @var string |
||
40 | */ |
||
41 | private $_createTempTableSql; |
||
42 | |||
43 | /** |
||
44 | * @var string |
||
45 | */ |
||
46 | private $_dropTempTableSql; |
||
47 | |||
48 | /** |
||
49 | * @var string |
||
50 | */ |
||
51 | private $_insertSql; |
||
52 | |||
53 | /** |
||
54 | * Initializes a new <tt>MultiTableDeleteExecutor</tt>. |
||
55 | * |
||
56 | * Internal note: Any SQL construction and preparation takes place in the constructor for |
||
57 | * best performance. With a query cache the executor will be cached. |
||
58 | * |
||
59 | * @param \Doctrine\ORM\Query\AST\Node $AST The root AST node of the DQL query. |
||
60 | * @param \Doctrine\ORM\Query\SqlWalker $sqlWalker The walker used for SQL generation from the AST. |
||
61 | */ |
||
62 | 2 | public function __construct(AST\Node $AST, $sqlWalker) |
|
63 | { |
||
64 | 2 | $em = $sqlWalker->getEntityManager(); |
|
65 | 2 | $conn = $em->getConnection(); |
|
66 | 2 | $platform = $conn->getDatabasePlatform(); |
|
67 | 2 | $quoteStrategy = $em->getConfiguration()->getQuoteStrategy(); |
|
68 | |||
69 | 2 | $primaryClass = $em->getClassMetadata($AST->deleteClause->abstractSchemaName); |
|
70 | 2 | $primaryDqlAlias = $AST->deleteClause->aliasIdentificationVariable; |
|
71 | 2 | $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); |
|
72 | |||
73 | 2 | $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); |
|
74 | 2 | $idColumnNames = $rootClass->getIdentifierColumnNames(); |
|
75 | 2 | $idColumnList = implode(', ', $idColumnNames); |
|
76 | |||
77 | // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() |
||
78 | 2 | $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $primaryDqlAlias); |
|
79 | |||
80 | 2 | $this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')' |
|
81 | 2 | . ' SELECT t0.' . implode(', t0.', $idColumnNames); |
|
82 | |||
83 | 2 | $rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $primaryDqlAlias); |
|
84 | 2 | $fromClause = new AST\FromClause([new AST\IdentificationVariableDeclaration($rangeDecl, null, [])]); |
|
85 | 2 | $this->_insertSql .= $sqlWalker->walkFromClause($fromClause); |
|
86 | |||
87 | // Append WHERE clause, if there is one. |
||
88 | 2 | if ($AST->whereClause) { |
|
89 | $this->_insertSql .= $sqlWalker->walkWhereClause($AST->whereClause); |
||
0 ignored issues
–
show
|
|||
90 | } |
||
91 | |||
92 | // 2. Create ID subselect statement used in DELETE ... WHERE ... IN (subselect) |
||
93 | 2 | $idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable; |
|
94 | |||
95 | // 3. Create and store DELETE statements |
||
96 | 2 | $classNames = array_merge($primaryClass->parentClasses, [$primaryClass->name], $primaryClass->subClasses); |
|
97 | 2 | foreach (array_reverse($classNames) as $className) { |
|
98 | 2 | $tableName = $quoteStrategy->getTableName($em->getClassMetadata($className), $platform); |
|
99 | 2 | $this->_sqlStatements[] = 'DELETE FROM ' . $tableName |
|
100 | 2 | . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')'; |
|
101 | } |
||
102 | |||
103 | // 4. Store DDL for temporary identifier table. |
||
104 | 2 | $columnDefinitions = []; |
|
105 | 2 | View Code Duplication | foreach ($idColumnNames as $idColumnName) { |
106 | 2 | $columnDefinitions[$idColumnName] = [ |
|
107 | 2 | 'notnull' => true, |
|
108 | 2 | 'type' => Type::getType(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $em)), |
|
109 | ]; |
||
110 | } |
||
111 | 2 | $this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' |
|
112 | 2 | . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; |
|
113 | 2 | $this->_dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable); |
|
114 | 2 | } |
|
115 | |||
116 | /** |
||
117 | * {@inheritDoc} |
||
118 | */ |
||
119 | 2 | public function execute(Connection $conn, array $params, array $types) |
|
120 | { |
||
121 | // Create temporary id table |
||
122 | 2 | $conn->executeUpdate($this->_createTempTableSql); |
|
123 | |||
124 | try { |
||
125 | // Insert identifiers |
||
126 | 2 | $numDeleted = $conn->executeUpdate($this->_insertSql, $params, $types); |
|
127 | |||
128 | // Execute DELETE statements |
||
129 | 2 | foreach ($this->_sqlStatements as $sql) { |
|
130 | 2 | $conn->executeUpdate($sql); |
|
131 | } |
||
132 | } catch (\Exception $exception) { |
||
133 | // FAILURE! Drop temporary table to avoid possible collisions |
||
134 | $conn->executeUpdate($this->_dropTempTableSql); |
||
135 | |||
136 | // Re-throw exception |
||
137 | throw $exception; |
||
138 | } |
||
139 | |||
140 | // Drop temporary table |
||
141 | 2 | $conn->executeUpdate($this->_dropTempTableSql); |
|
142 | |||
143 | 2 | return $numDeleted; |
|
144 | } |
||
145 | } |
||
146 |
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.