PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.35.1
MailPoet – Newsletters, Email Marketing, and Automation v5.35.1
5.36.1 5.36.0 5.35.1 5.35.0 5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / vendor-prefixed / doctrine / orm / src / Persisters / Entity / JoinedSubclassPersister.php
mailpoet / vendor-prefixed / doctrine / orm / src / Persisters / Entity Last commit date
AbstractEntityInheritancePersister.php 9 months ago BasicEntityPersister.php 9 months ago CachedPersisterContext.php 9 months ago EntityPersister.php 9 months ago JoinedSubclassPersister.php 9 months ago SingleTablePersister.php 9 months ago index.php 9 months ago
JoinedSubclassPersister.php
408 lines
1 <?php
2 declare (strict_types=1);
3 namespace MailPoetVendor\Doctrine\ORM\Persisters\Entity;
4 if (!defined('ABSPATH')) exit;
5 use MailPoetVendor\Doctrine\Common\Collections\Criteria;
6 use MailPoetVendor\Doctrine\DBAL\LockMode;
7 use MailPoetVendor\Doctrine\DBAL\Types\Type;
8 use MailPoetVendor\Doctrine\DBAL\Types\Types;
9 use MailPoetVendor\Doctrine\ORM\Internal\SQLResultCasing;
10 use MailPoetVendor\Doctrine\ORM\Mapping\ClassMetadata;
11 use MailPoetVendor\Doctrine\ORM\Utility\LockSqlHelper;
12 use MailPoetVendor\Doctrine\ORM\Utility\PersisterHelper;
13 use LengthException;
14 use function array_combine;
15 use function array_keys;
16 use function array_values;
17 use function implode;
18 class JoinedSubclassPersister extends AbstractEntityInheritancePersister
19 {
20 use LockSqlHelper;
21 use SQLResultCasing;
22 private $owningTableMap = [];
23 private $quotedTableMap = [];
24 protected function getDiscriminatorColumnTableName()
25 {
26 $class = $this->class->name !== $this->class->rootEntityName ? $this->em->getClassMetadata($this->class->rootEntityName) : $this->class;
27 return $class->getTableName();
28 }
29 private function getVersionedClassMetadata() : ClassMetadata
30 {
31 if ($this->class->versionField !== null && isset($this->class->fieldMappings[$this->class->versionField]['inherited'])) {
32 $definingClassName = $this->class->fieldMappings[$this->class->versionField]['inherited'];
33 return $this->em->getClassMetadata($definingClassName);
34 }
35 return $this->class;
36 }
37 public function getOwningTable($fieldName)
38 {
39 if (isset($this->owningTableMap[$fieldName])) {
40 return $this->owningTableMap[$fieldName];
41 }
42 switch (\true) {
43 case isset($this->class->associationMappings[$fieldName]['inherited']):
44 $cm = $this->em->getClassMetadata($this->class->associationMappings[$fieldName]['inherited']);
45 break;
46 case isset($this->class->fieldMappings[$fieldName]['inherited']):
47 $cm = $this->em->getClassMetadata($this->class->fieldMappings[$fieldName]['inherited']);
48 break;
49 default:
50 $cm = $this->class;
51 break;
52 }
53 $tableName = $cm->getTableName();
54 $quotedTableName = $this->quoteStrategy->getTableName($cm, $this->platform);
55 $this->owningTableMap[$fieldName] = $tableName;
56 $this->quotedTableMap[$tableName] = $quotedTableName;
57 return $tableName;
58 }
59 public function executeInserts()
60 {
61 if (!$this->queuedInserts) {
62 return;
63 }
64 $uow = $this->em->getUnitOfWork();
65 $idGenerator = $this->class->idGenerator;
66 $isPostInsertId = $idGenerator->isPostInsertGenerator();
67 $rootClass = $this->class->name !== $this->class->rootEntityName ? $this->em->getClassMetadata($this->class->rootEntityName) : $this->class;
68 // Prepare statement for the root table
69 $rootPersister = $this->em->getUnitOfWork()->getEntityPersister($rootClass->name);
70 $rootTableName = $rootClass->getTableName();
71 $rootTableStmt = $this->conn->prepare($rootPersister->getInsertSQL());
72 // Prepare statements for sub tables.
73 $subTableStmts = [];
74 if ($rootClass !== $this->class) {
75 $subTableStmts[$this->class->getTableName()] = $this->conn->prepare($this->getInsertSQL());
76 }
77 foreach ($this->class->parentClasses as $parentClassName) {
78 $parentClass = $this->em->getClassMetadata($parentClassName);
79 $parentTableName = $parentClass->getTableName();
80 if ($parentClass !== $rootClass) {
81 $parentPersister = $this->em->getUnitOfWork()->getEntityPersister($parentClassName);
82 $subTableStmts[$parentTableName] = $this->conn->prepare($parentPersister->getInsertSQL());
83 }
84 }
85 // Execute all inserts. For each entity:
86 // 1) Insert on root table
87 // 2) Insert on sub tables
88 foreach ($this->queuedInserts as $key => $entity) {
89 $insertData = $this->prepareInsertData($entity);
90 // Execute insert on root table
91 $paramIndex = 1;
92 foreach ($insertData[$rootTableName] as $columnName => $value) {
93 $rootTableStmt->bindValue($paramIndex++, $value, $this->columnTypes[$columnName]);
94 }
95 $rootTableStmt->executeStatement();
96 if ($isPostInsertId) {
97 $generatedId = $idGenerator->generateId($this->em, $entity);
98 $id = [$this->class->identifier[0] => $generatedId];
99 $uow->assignPostInsertId($entity, $generatedId);
100 } else {
101 $id = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
102 }
103 // Execute inserts on subtables.
104 // The order doesn't matter because all child tables link to the root table via FK.
105 foreach ($subTableStmts as $tableName => $stmt) {
106 $paramIndex = 1;
107 $data = $insertData[$tableName] ?? [];
108 foreach ($id as $idName => $idVal) {
109 $type = $this->columnTypes[$idName] ?? Types::STRING;
110 $stmt->bindValue($paramIndex++, $idVal, $type);
111 }
112 foreach ($data as $columnName => $value) {
113 if (!isset($id[$columnName])) {
114 $stmt->bindValue($paramIndex++, $value, $this->columnTypes[$columnName]);
115 }
116 }
117 $stmt->executeStatement();
118 }
119 if ($this->class->requiresFetchAfterChange) {
120 $this->assignDefaultVersionAndUpsertableValues($entity, $id);
121 }
122 // Unset this queued insert, so that the prepareUpdateData() method (called via prepareInsertData() method)
123 // knows right away (for the next entity already) that the current entity has been written to the database
124 // and no extra updates need to be scheduled to refer to it.
125 //
126 // In \MailPoetVendor\Doctrine\ORM\UnitOfWork::executeInserts(), the UoW already removed entities
127 // from its own list (\Doctrine\ORM\UnitOfWork::$entityInsertions) right after they
128 // were given to our addInsert() method.
129 unset($this->queuedInserts[$key]);
130 }
131 }
132 public function update($entity)
133 {
134 $updateData = $this->prepareUpdateData($entity);
135 if (!$updateData) {
136 return;
137 }
138 $isVersioned = $this->class->isVersioned;
139 $versionedClass = $this->getVersionedClassMetadata();
140 $versionedTable = $versionedClass->getTableName();
141 foreach ($updateData as $tableName => $data) {
142 $tableName = $this->quotedTableMap[$tableName];
143 $versioned = $isVersioned && $versionedTable === $tableName;
144 $this->updateTable($entity, $tableName, $data, $versioned);
145 }
146 if ($this->class->requiresFetchAfterChange) {
147 // Make sure the table with the version column is updated even if no columns on that
148 // table were affected.
149 if ($isVersioned && !isset($updateData[$versionedTable])) {
150 $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform);
151 $this->updateTable($entity, $tableName, [], \true);
152 }
153 $identifiers = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
154 $this->assignDefaultVersionAndUpsertableValues($entity, $identifiers);
155 }
156 }
157 public function delete($entity)
158 {
159 $identifier = $this->em->getUnitOfWork()->getEntityIdentifier($entity);
160 $id = array_combine($this->class->getIdentifierColumnNames(), $identifier);
161 $types = $this->getClassIdentifiersTypes($this->class);
162 $this->deleteJoinTableRecords($identifier, $types);
163 // If the database platform supports FKs, just
164 // delete the row from the root table. Cascades do the rest.
165 // @phpstan-ignore method.deprecated
166 if ($this->platform->supportsForeignKeyConstraints()) {
167 $rootClass = $this->em->getClassMetadata($this->class->rootEntityName);
168 $rootTable = $this->quoteStrategy->getTableName($rootClass, $this->platform);
169 $rootTypes = $this->getClassIdentifiersTypes($rootClass);
170 return (bool) $this->conn->delete($rootTable, $id, $rootTypes);
171 }
172 // Delete from all tables individually, starting from this class' table up to the root table.
173 $rootTable = $this->quoteStrategy->getTableName($this->class, $this->platform);
174 $rootTypes = $this->getClassIdentifiersTypes($this->class);
175 $affectedRows = $this->conn->delete($rootTable, $id, $rootTypes);
176 foreach ($this->class->parentClasses as $parentClass) {
177 $parentMetadata = $this->em->getClassMetadata($parentClass);
178 $parentTable = $this->quoteStrategy->getTableName($parentMetadata, $this->platform);
179 $parentTypes = $this->getClassIdentifiersTypes($parentMetadata);
180 $this->conn->delete($parentTable, $id, $parentTypes);
181 }
182 return (bool) $affectedRows;
183 }
184 public function getSelectSQL($criteria, $assoc = null, $lockMode = null, $limit = null, $offset = null, ?array $orderBy = null)
185 {
186 $this->switchPersisterContext($offset, $limit);
187 $baseTableAlias = $this->getSQLTableAlias($this->class->name);
188 $joinSql = $this->getJoinSql($baseTableAlias);
189 if ($assoc !== null && $assoc['type'] === ClassMetadata::MANY_TO_MANY) {
190 $joinSql .= $this->getSelectManyToManyJoinSQL($assoc);
191 }
192 $conditionSql = $criteria instanceof Criteria ? $this->getSelectConditionCriteriaSQL($criteria) : $this->getSelectConditionSQL($criteria, $assoc);
193 $filterSql = $this->generateFilterConditionSQL($this->em->getClassMetadata($this->class->rootEntityName), $this->getSQLTableAlias($this->class->rootEntityName));
194 // If the current class in the root entity, add the filters
195 if ($filterSql) {
196 $conditionSql .= $conditionSql ? ' AND ' . $filterSql : $filterSql;
197 }
198 $orderBySql = '';
199 if ($assoc !== null && isset($assoc['orderBy'])) {
200 $orderBy = $assoc['orderBy'];
201 }
202 if ($orderBy) {
203 $orderBySql = $this->getOrderBySQL($orderBy, $baseTableAlias);
204 }
205 $lockSql = '';
206 switch ($lockMode) {
207 case LockMode::PESSIMISTIC_READ:
208 $lockSql = ' ' . $this->getReadLockSQL($this->platform);
209 break;
210 case LockMode::PESSIMISTIC_WRITE:
211 $lockSql = ' ' . $this->getWriteLockSQL($this->platform);
212 break;
213 }
214 $tableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
215 $from = ' FROM ' . $tableName . ' ' . $baseTableAlias;
216 $where = $conditionSql !== '' ? ' WHERE ' . $conditionSql : '';
217 $lock = $this->platform->appendLockHint($from, $lockMode ?? LockMode::NONE);
218 $columnList = $this->getSelectColumnsSQL();
219 $query = 'SELECT ' . $columnList . $lock . $joinSql . $where . $orderBySql;
220 return $this->platform->modifyLimitQuery($query, $limit, $offset ?? 0) . $lockSql;
221 }
222 public function getCountSQL($criteria = [])
223 {
224 $tableName = $this->quoteStrategy->getTableName($this->class, $this->platform);
225 $baseTableAlias = $this->getSQLTableAlias($this->class->name);
226 $joinSql = $this->getJoinSql($baseTableAlias);
227 $conditionSql = $criteria instanceof Criteria ? $this->getSelectConditionCriteriaSQL($criteria) : $this->getSelectConditionSQL($criteria);
228 $filterSql = $this->generateFilterConditionSQL($this->em->getClassMetadata($this->class->rootEntityName), $this->getSQLTableAlias($this->class->rootEntityName));
229 if ($filterSql !== '') {
230 $conditionSql = $conditionSql ? $conditionSql . ' AND ' . $filterSql : $filterSql;
231 }
232 return 'SELECT COUNT(*) ' . 'FROM ' . $tableName . ' ' . $baseTableAlias . $joinSql . (empty($conditionSql) ? '' : ' WHERE ' . $conditionSql);
233 }
234 protected function getLockTablesSql($lockMode)
235 {
236 $joinSql = '';
237 $identifierColumns = $this->class->getIdentifierColumnNames();
238 $baseTableAlias = $this->getSQLTableAlias($this->class->name);
239 // INNER JOIN parent tables
240 foreach ($this->class->parentClasses as $parentClassName) {
241 $conditions = [];
242 $tableAlias = $this->getSQLTableAlias($parentClassName);
243 $parentClass = $this->em->getClassMetadata($parentClassName);
244 $joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON ';
245 foreach ($identifierColumns as $idColumn) {
246 $conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
247 }
248 $joinSql .= implode(' AND ', $conditions);
249 }
250 return parent::getLockTablesSql($lockMode) . $joinSql;
251 }
252 protected function getSelectColumnsSQL()
253 {
254 // Create the column list fragment only once
255 if ($this->currentPersisterContext->selectColumnListSql !== null && $this->isFilterHashUpToDate()) {
256 return $this->currentPersisterContext->selectColumnListSql;
257 }
258 $columnList = [];
259 $discrColumn = $this->class->getDiscriminatorColumn();
260 $discrColumnName = $discrColumn['name'];
261 $discrColumnType = $discrColumn['type'];
262 $baseTableAlias = $this->getSQLTableAlias($this->class->name);
263 $resultColumnName = $this->getSQLResultCasing($this->platform, $discrColumnName);
264 $this->currentPersisterContext->rsm->addEntityResult($this->class->name, 'r');
265 $this->currentPersisterContext->rsm->setDiscriminatorColumn('r', $resultColumnName);
266 $this->currentPersisterContext->rsm->addMetaResult('r', $resultColumnName, $discrColumnName, \false, $discrColumnType);
267 // Add regular columns
268 foreach ($this->class->fieldMappings as $fieldName => $mapping) {
269 $class = isset($mapping['inherited']) ? $this->em->getClassMetadata($mapping['inherited']) : $this->class;
270 $columnList[] = $this->getSelectColumnSQL($fieldName, $class);
271 }
272 // Add foreign key columns
273 foreach ($this->class->associationMappings as $mapping) {
274 if (!$mapping['isOwningSide'] || !($mapping['type'] & ClassMetadata::TO_ONE)) {
275 continue;
276 }
277 $tableAlias = isset($mapping['inherited']) ? $this->getSQLTableAlias($mapping['inherited']) : $baseTableAlias;
278 $targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
279 foreach ($mapping['joinColumns'] as $joinColumn) {
280 $columnList[] = $this->getSelectJoinColumnSQL($tableAlias, $joinColumn['name'], $this->quoteStrategy->getJoinColumnName($joinColumn, $this->class, $this->platform), PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em));
281 }
282 }
283 // Add discriminator column (DO NOT ALIAS, see AbstractEntityInheritancePersister#processSQLResult).
284 $tableAlias = $this->class->rootEntityName === $this->class->name ? $baseTableAlias : $this->getSQLTableAlias($this->class->rootEntityName);
285 $columnList[] = $tableAlias . '.' . $discrColumnName;
286 // sub tables
287 foreach ($this->class->subClasses as $subClassName) {
288 $subClass = $this->em->getClassMetadata($subClassName);
289 $tableAlias = $this->getSQLTableAlias($subClassName);
290 // Add subclass columns
291 foreach ($subClass->fieldMappings as $fieldName => $mapping) {
292 if (isset($mapping['inherited'])) {
293 continue;
294 }
295 $columnList[] = $this->getSelectColumnSQL($fieldName, $subClass);
296 }
297 // Add join columns (foreign keys)
298 foreach ($subClass->associationMappings as $mapping) {
299 if (!$mapping['isOwningSide'] || !($mapping['type'] & ClassMetadata::TO_ONE) || isset($mapping['inherited'])) {
300 continue;
301 }
302 $targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
303 foreach ($mapping['joinColumns'] as $joinColumn) {
304 $columnList[] = $this->getSelectJoinColumnSQL($tableAlias, $joinColumn['name'], $this->quoteStrategy->getJoinColumnName($joinColumn, $subClass, $this->platform), PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em));
305 }
306 }
307 }
308 $this->currentPersisterContext->selectColumnListSql = implode(', ', $columnList);
309 $this->updateFilterHash();
310 return $this->currentPersisterContext->selectColumnListSql;
311 }
312 protected function getInsertColumnList()
313 {
314 // Identifier columns must always come first in the column list of subclasses.
315 $columns = $this->class->parentClasses ? $this->class->getIdentifierColumnNames() : [];
316 foreach ($this->class->reflFields as $name => $field) {
317 if (isset($this->class->fieldMappings[$name]['inherited']) && !isset($this->class->fieldMappings[$name]['id']) || isset($this->class->associationMappings[$name]['inherited']) || $this->class->isVersioned && $this->class->versionField === $name || isset($this->class->embeddedClasses[$name]) || isset($this->class->fieldMappings[$name]['notInsertable'])) {
318 continue;
319 }
320 if (isset($this->class->associationMappings[$name])) {
321 $assoc = $this->class->associationMappings[$name];
322 if ($assoc['type'] & ClassMetadata::TO_ONE && $assoc['isOwningSide']) {
323 foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) {
324 $columns[] = $sourceCol;
325 }
326 }
327 } elseif ($this->class->name !== $this->class->rootEntityName || !$this->class->isIdGeneratorIdentity() || $this->class->identifier[0] !== $name) {
328 $columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform);
329 $this->columnTypes[$name] = $this->class->fieldMappings[$name]['type'];
330 }
331 }
332 // Add discriminator column if it is the topmost class.
333 if ($this->class->name === $this->class->rootEntityName) {
334 $columns[] = $this->class->getDiscriminatorColumn()['name'];
335 }
336 return $columns;
337 }
338 protected function assignDefaultVersionAndUpsertableValues($entity, array $id)
339 {
340 $values = $this->fetchVersionAndNotUpsertableValues($this->getVersionedClassMetadata(), $id);
341 foreach ($values as $field => $value) {
342 $value = Type::getType($this->class->fieldMappings[$field]['type'])->convertToPHPValue($value, $this->platform);
343 $this->class->setFieldValue($entity, $field, $value);
344 }
345 }
346 protected function fetchVersionAndNotUpsertableValues($versionedClass, array $id)
347 {
348 $columnNames = [];
349 foreach ($this->class->fieldMappings as $key => $column) {
350 $class = null;
351 if ($this->class->isVersioned && $key === $versionedClass->versionField) {
352 $class = $versionedClass;
353 } elseif (isset($column['generated'])) {
354 $class = isset($column['inherited']) ? $this->em->getClassMetadata($column['inherited']) : $this->class;
355 } else {
356 continue;
357 }
358 $columnNames[$key] = $this->getSelectColumnSQL($key, $class);
359 }
360 $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform);
361 $baseTableAlias = $this->getSQLTableAlias($this->class->name);
362 $joinSql = $this->getJoinSql($baseTableAlias);
363 $identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->platform);
364 foreach ($identifier as $i => $idValue) {
365 $identifier[$i] = $baseTableAlias . '.' . $idValue;
366 }
367 $sql = 'SELECT ' . implode(', ', $columnNames) . ' FROM ' . $tableName . ' ' . $baseTableAlias . $joinSql . ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?';
368 $flatId = $this->identifierFlattener->flattenIdentifier($versionedClass, $id);
369 $values = $this->conn->fetchNumeric($sql, array_values($flatId), $this->extractIdentifierTypes($id, $versionedClass));
370 if ($values === \false) {
371 throw new LengthException('Unexpected empty result for database query.');
372 }
373 $values = array_combine(array_keys($columnNames), $values);
374 if (!$values) {
375 throw new LengthException('Unexpected number of database columns.');
376 }
377 return $values;
378 }
379 private function getJoinSql(string $baseTableAlias) : string
380 {
381 $joinSql = '';
382 $identifierColumn = $this->class->getIdentifierColumnNames();
383 // INNER JOIN parent tables
384 foreach ($this->class->parentClasses as $parentClassName) {
385 $conditions = [];
386 $parentClass = $this->em->getClassMetadata($parentClassName);
387 $tableAlias = $this->getSQLTableAlias($parentClassName);
388 $joinSql .= ' INNER JOIN ' . $this->quoteStrategy->getTableName($parentClass, $this->platform) . ' ' . $tableAlias . ' ON ';
389 foreach ($identifierColumn as $idColumn) {
390 $conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
391 }
392 $joinSql .= implode(' AND ', $conditions);
393 }
394 // OUTER JOIN sub tables
395 foreach ($this->class->subClasses as $subClassName) {
396 $conditions = [];
397 $subClass = $this->em->getClassMetadata($subClassName);
398 $tableAlias = $this->getSQLTableAlias($subClassName);
399 $joinSql .= ' LEFT JOIN ' . $this->quoteStrategy->getTableName($subClass, $this->platform) . ' ' . $tableAlias . ' ON ';
400 foreach ($identifierColumn as $idColumn) {
401 $conditions[] = $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
402 }
403 $joinSql .= implode(' AND ', $conditions);
404 }
405 return $joinSql;
406 }
407 }
408