AST
9 months ago
Exec
9 months ago
Expr
9 months ago
Filter
9 months ago
Expr.php
9 months ago
FilterCollection.php
9 months ago
Lexer.php
9 months ago
OutputWalker.php
9 months ago
Parameter.php
9 months ago
ParameterTypeInferer.php
9 months ago
Parser.php
9 months ago
ParserResult.php
9 months ago
Printer.php
9 months ago
QueryException.php
9 months ago
QueryExpressionVisitor.php
9 months ago
ResultSetMapping.php
9 months ago
ResultSetMappingBuilder.php
9 months ago
SqlOutputWalker.php
9 months ago
SqlWalker.php
9 months ago
TokenType.php
9 months ago
TreeWalker.php
9 months ago
TreeWalkerAdapter.php
9 months ago
TreeWalkerChain.php
9 months ago
TreeWalkerChainIterator.php
9 months ago
index.php
9 months ago
ResultSetMappingBuilder.php
266 lines
| 1 | <?php |
| 2 | declare (strict_types=1); |
| 3 | namespace MailPoetVendor\Doctrine\ORM\Query; |
| 4 | if (!defined('ABSPATH')) exit; |
| 5 | use MailPoetVendor\Doctrine\DBAL\Types\Type; |
| 6 | use MailPoetVendor\Doctrine\ORM\EntityManagerInterface; |
| 7 | use MailPoetVendor\Doctrine\ORM\Internal\SQLResultCasing; |
| 8 | use MailPoetVendor\Doctrine\ORM\Mapping\ClassMetadata; |
| 9 | use MailPoetVendor\Doctrine\ORM\Mapping\ClassMetadataInfo; |
| 10 | use MailPoetVendor\Doctrine\ORM\Mapping\MappingException; |
| 11 | use MailPoetVendor\Doctrine\ORM\Utility\PersisterHelper; |
| 12 | use InvalidArgumentException; |
| 13 | use LogicException; |
| 14 | use function assert; |
| 15 | use function explode; |
| 16 | use function in_array; |
| 17 | use function sprintf; |
| 18 | use function str_contains; |
| 19 | use function strtolower; |
| 20 | class ResultSetMappingBuilder extends ResultSetMapping |
| 21 | { |
| 22 | use SQLResultCasing; |
| 23 | public const COLUMN_RENAMING_NONE = 1; |
| 24 | public const COLUMN_RENAMING_CUSTOM = 2; |
| 25 | public const COLUMN_RENAMING_INCREMENT = 3; |
| 26 | private $sqlCounter = 0; |
| 27 | private $em; |
| 28 | private $defaultRenameMode; |
| 29 | public function __construct(EntityManagerInterface $em, $defaultRenameMode = self::COLUMN_RENAMING_NONE) |
| 30 | { |
| 31 | $this->em = $em; |
| 32 | $this->defaultRenameMode = $defaultRenameMode; |
| 33 | } |
| 34 | public function addRootEntityFromClassMetadata($class, $alias, $renamedColumns = [], $renameMode = null) |
| 35 | { |
| 36 | $renameMode = $renameMode ?: $this->defaultRenameMode; |
| 37 | $columnAliasMap = $this->getColumnAliasMap($class, $renameMode, $renamedColumns); |
| 38 | $this->addEntityResult($class, $alias); |
| 39 | $this->addAllClassFields($class, $alias, $columnAliasMap); |
| 40 | } |
| 41 | public function addJoinedEntityFromClassMetadata($class, $alias, $parentAlias, $relation, $renamedColumns = [], $renameMode = null) |
| 42 | { |
| 43 | $renameMode = $renameMode ?: $this->defaultRenameMode; |
| 44 | $columnAliasMap = $this->getColumnAliasMap($class, $renameMode, $renamedColumns); |
| 45 | $this->addJoinedEntityResult($class, $alias, $parentAlias, $relation); |
| 46 | $this->addAllClassFields($class, $alias, $columnAliasMap); |
| 47 | } |
| 48 | protected function addAllClassFields($class, $alias, $columnAliasMap = []) |
| 49 | { |
| 50 | $classMetadata = $this->em->getClassMetadata($class); |
| 51 | $platform = $this->em->getConnection()->getDatabasePlatform(); |
| 52 | if (!$this->isInheritanceSupported($classMetadata)) { |
| 53 | throw new InvalidArgumentException('ResultSetMapping builder does not currently support your inheritance scheme.'); |
| 54 | } |
| 55 | foreach ($classMetadata->getColumnNames() as $columnName) { |
| 56 | $propertyName = $classMetadata->getFieldName($columnName); |
| 57 | $columnAlias = $this->getSQLResultCasing($platform, $columnAliasMap[$columnName]); |
| 58 | if (isset($this->fieldMappings[$columnAlias])) { |
| 59 | throw new InvalidArgumentException(sprintf("The column '%s' conflicts with another column in the mapper.", $columnName)); |
| 60 | } |
| 61 | $this->addFieldResult($alias, $columnAlias, $propertyName); |
| 62 | $enumType = $classMetadata->getFieldMapping($propertyName)['enumType'] ?? null; |
| 63 | if (!empty($enumType)) { |
| 64 | $this->addEnumResult($columnAlias, $enumType); |
| 65 | } |
| 66 | } |
| 67 | foreach ($classMetadata->associationMappings as $associationMapping) { |
| 68 | if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadata::TO_ONE) { |
| 69 | $targetClass = $this->em->getClassMetadata($associationMapping['targetEntity']); |
| 70 | $isIdentifier = isset($associationMapping['id']) && $associationMapping['id'] === \true; |
| 71 | foreach ($associationMapping['joinColumns'] as $joinColumn) { |
| 72 | $columnName = $joinColumn['name']; |
| 73 | $columnAlias = $this->getSQLResultCasing($platform, $columnAliasMap[$columnName]); |
| 74 | $columnType = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); |
| 75 | if (isset($this->metaMappings[$columnAlias])) { |
| 76 | throw new InvalidArgumentException(sprintf("The column '%s' conflicts with another column in the mapper.", $columnAlias)); |
| 77 | } |
| 78 | $this->addMetaResult($alias, $columnAlias, $columnName, $isIdentifier, $columnType); |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | } |
| 83 | private function isInheritanceSupported(ClassMetadata $classMetadata) : bool |
| 84 | { |
| 85 | if ($classMetadata->isInheritanceTypeSingleTable() && in_array($classMetadata->name, $classMetadata->discriminatorMap, \true)) { |
| 86 | return \true; |
| 87 | } |
| 88 | return !($classMetadata->isInheritanceTypeSingleTable() || $classMetadata->isInheritanceTypeJoined()); |
| 89 | } |
| 90 | private function getColumnAlias(string $columnName, int $mode, array $customRenameColumns) : string |
| 91 | { |
| 92 | switch ($mode) { |
| 93 | case self::COLUMN_RENAMING_INCREMENT: |
| 94 | return $columnName . $this->sqlCounter++; |
| 95 | case self::COLUMN_RENAMING_CUSTOM: |
| 96 | return $customRenameColumns[$columnName] ?? $columnName; |
| 97 | case self::COLUMN_RENAMING_NONE: |
| 98 | return $columnName; |
| 99 | default: |
| 100 | throw new InvalidArgumentException(sprintf('%d is not a valid value for $mode', $mode)); |
| 101 | } |
| 102 | } |
| 103 | private function getColumnAliasMap(string $className, int $mode, array $customRenameColumns) : array |
| 104 | { |
| 105 | if ($customRenameColumns) { |
| 106 | // for BC with 2.2-2.3 API |
| 107 | $mode = self::COLUMN_RENAMING_CUSTOM; |
| 108 | } |
| 109 | $columnAlias = []; |
| 110 | $class = $this->em->getClassMetadata($className); |
| 111 | foreach ($class->getColumnNames() as $columnName) { |
| 112 | $columnAlias[$columnName] = $this->getColumnAlias($columnName, $mode, $customRenameColumns); |
| 113 | } |
| 114 | foreach ($class->associationMappings as $associationMapping) { |
| 115 | if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadata::TO_ONE) { |
| 116 | foreach ($associationMapping['joinColumns'] as $joinColumn) { |
| 117 | $columnName = $joinColumn['name']; |
| 118 | $columnAlias[$columnName] = $this->getColumnAlias($columnName, $mode, $customRenameColumns); |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | return $columnAlias; |
| 123 | } |
| 124 | public function addNamedNativeQueryMapping(ClassMetadataInfo $class, array $queryMapping) |
| 125 | { |
| 126 | if (isset($queryMapping['resultClass'])) { |
| 127 | return $this->addNamedNativeQueryResultClassMapping($class, $queryMapping['resultClass']); |
| 128 | } |
| 129 | return $this->addNamedNativeQueryResultSetMapping($class, $queryMapping['resultSetMapping']); |
| 130 | } |
| 131 | public function addNamedNativeQueryResultClassMapping(ClassMetadataInfo $class, $resultClassName) |
| 132 | { |
| 133 | $classMetadata = $this->em->getClassMetadata($resultClassName); |
| 134 | assert($classMetadata->reflClass !== null); |
| 135 | $shortName = $classMetadata->reflClass->getShortName(); |
| 136 | $alias = strtolower($shortName[0]) . '0'; |
| 137 | $this->addEntityResult($class->name, $alias); |
| 138 | if ($classMetadata->discriminatorColumn) { |
| 139 | $discrColumn = $classMetadata->discriminatorColumn; |
| 140 | $this->setDiscriminatorColumn($alias, $discrColumn['name']); |
| 141 | $this->addMetaResult($alias, $discrColumn['name'], $discrColumn['fieldName'], \false, $discrColumn['type']); |
| 142 | } |
| 143 | foreach ($classMetadata->getColumnNames() as $key => $columnName) { |
| 144 | $propertyName = $classMetadata->getFieldName($columnName); |
| 145 | $this->addFieldResult($alias, $columnName, $propertyName); |
| 146 | } |
| 147 | foreach ($classMetadata->associationMappings as $associationMapping) { |
| 148 | if ($associationMapping['isOwningSide'] && $associationMapping['type'] & ClassMetadata::TO_ONE) { |
| 149 | $targetClass = $this->em->getClassMetadata($associationMapping['targetEntity']); |
| 150 | foreach ($associationMapping['joinColumns'] as $joinColumn) { |
| 151 | $columnName = $joinColumn['name']; |
| 152 | $columnType = PersisterHelper::getTypeOfColumn($joinColumn['referencedColumnName'], $targetClass, $this->em); |
| 153 | $this->addMetaResult($alias, $columnName, $columnName, $classMetadata->isIdentifier($columnName), $columnType); |
| 154 | } |
| 155 | } |
| 156 | } |
| 157 | return $this; |
| 158 | } |
| 159 | public function addNamedNativeQueryResultSetMapping(ClassMetadataInfo $class, $resultSetMappingName) |
| 160 | { |
| 161 | if ($class->reflClass === null) { |
| 162 | throw new LogicException('Given class metadata has now class reflector.'); |
| 163 | } |
| 164 | $counter = 0; |
| 165 | $resultMapping = $class->getSqlResultSetMapping($resultSetMappingName); |
| 166 | $rootShortName = $class->reflClass->getShortName(); |
| 167 | $rootAlias = strtolower($rootShortName[0]) . $counter; |
| 168 | if (isset($resultMapping['entities'])) { |
| 169 | foreach ($resultMapping['entities'] as $entityMapping) { |
| 170 | $classMetadata = $this->em->getClassMetadata($entityMapping['entityClass']); |
| 171 | assert($classMetadata->reflClass !== null); |
| 172 | if ($class->reflClass->name === $classMetadata->reflClass->name) { |
| 173 | $this->addEntityResult($classMetadata->name, $rootAlias); |
| 174 | $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $rootAlias); |
| 175 | } else { |
| 176 | $shortName = $classMetadata->reflClass->getShortName(); |
| 177 | $joinAlias = strtolower($shortName[0]) . ++$counter; |
| 178 | $associations = $class->getAssociationsByTargetClass($classMetadata->name); |
| 179 | $this->addNamedNativeQueryEntityResultMapping($classMetadata, $entityMapping, $joinAlias); |
| 180 | foreach ($associations as $relation => $mapping) { |
| 181 | $this->addJoinedEntityResult($mapping['targetEntity'], $joinAlias, $rootAlias, $relation); |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | } |
| 186 | if (isset($resultMapping['columns'])) { |
| 187 | foreach ($resultMapping['columns'] as $entityMapping) { |
| 188 | $type = isset($class->fieldNames[$entityMapping['name']]) ? PersisterHelper::getTypeOfColumn($entityMapping['name'], $class, $this->em) : 'string'; |
| 189 | $this->addScalarResult($entityMapping['name'], $entityMapping['name'], $type); |
| 190 | } |
| 191 | } |
| 192 | return $this; |
| 193 | } |
| 194 | public function addNamedNativeQueryEntityResultMapping(ClassMetadataInfo $classMetadata, array $entityMapping, $alias) |
| 195 | { |
| 196 | if (isset($entityMapping['discriminatorColumn']) && $entityMapping['discriminatorColumn']) { |
| 197 | $discriminatorColumn = $entityMapping['discriminatorColumn']; |
| 198 | $discriminatorType = $classMetadata->getDiscriminatorColumn()['type']; |
| 199 | $this->setDiscriminatorColumn($alias, $discriminatorColumn); |
| 200 | $this->addMetaResult($alias, $discriminatorColumn, $discriminatorColumn, \false, $discriminatorType); |
| 201 | } |
| 202 | if (isset($entityMapping['fields']) && !empty($entityMapping['fields'])) { |
| 203 | foreach ($entityMapping['fields'] as $field) { |
| 204 | $fieldName = $field['name']; |
| 205 | $relation = null; |
| 206 | if (str_contains($fieldName, '.')) { |
| 207 | [$relation, $fieldName] = explode('.', $fieldName); |
| 208 | } |
| 209 | if ($relation !== null && isset($classMetadata->associationMappings[$relation])) { |
| 210 | if ($relation) { |
| 211 | $associationMapping = $classMetadata->associationMappings[$relation]; |
| 212 | $joinAlias = $alias . $relation; |
| 213 | $parentAlias = $alias; |
| 214 | $this->addJoinedEntityResult($associationMapping['targetEntity'], $joinAlias, $parentAlias, $relation); |
| 215 | $this->addFieldResult($joinAlias, $field['column'], $fieldName); |
| 216 | } else { |
| 217 | $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name); |
| 218 | } |
| 219 | } else { |
| 220 | if (!isset($classMetadata->fieldMappings[$fieldName])) { |
| 221 | throw new InvalidArgumentException("Entity '" . $classMetadata->name . "' has no field '" . $fieldName . "'. "); |
| 222 | } |
| 223 | $this->addFieldResult($alias, $field['column'], $fieldName, $classMetadata->name); |
| 224 | } |
| 225 | } |
| 226 | } else { |
| 227 | foreach ($classMetadata->getColumnNames() as $columnName) { |
| 228 | $propertyName = $classMetadata->getFieldName($columnName); |
| 229 | $this->addFieldResult($alias, $columnName, $propertyName); |
| 230 | } |
| 231 | } |
| 232 | return $this; |
| 233 | } |
| 234 | public function generateSelectClause($tableAliases = []) |
| 235 | { |
| 236 | $sql = ''; |
| 237 | foreach ($this->columnOwnerMap as $columnName => $dqlAlias) { |
| 238 | $tableAlias = $tableAliases[$dqlAlias] ?? $dqlAlias; |
| 239 | if ($sql !== '') { |
| 240 | $sql .= ', '; |
| 241 | } |
| 242 | if (isset($this->fieldMappings[$columnName])) { |
| 243 | $class = $this->em->getClassMetadata($this->declaringClasses[$columnName]); |
| 244 | $fieldName = $this->fieldMappings[$columnName]; |
| 245 | $classFieldMapping = $class->fieldMappings[$fieldName]; |
| 246 | $columnSql = $tableAlias . '.' . $classFieldMapping['columnName']; |
| 247 | if (isset($classFieldMapping['requireSQLConversion']) && $classFieldMapping['requireSQLConversion'] === \true) { |
| 248 | $type = Type::getType($classFieldMapping['type']); |
| 249 | $columnSql = $type->convertToPHPValueSQL($columnSql, $this->em->getConnection()->getDatabasePlatform()); |
| 250 | } |
| 251 | $sql .= $columnSql; |
| 252 | } elseif (isset($this->metaMappings[$columnName])) { |
| 253 | $sql .= $tableAlias . '.' . $this->metaMappings[$columnName]; |
| 254 | } elseif (isset($this->discriminatorColumns[$dqlAlias])) { |
| 255 | $sql .= $tableAlias . '.' . $this->discriminatorColumns[$dqlAlias]; |
| 256 | } |
| 257 | $sql .= ' AS ' . $columnName; |
| 258 | } |
| 259 | return $sql; |
| 260 | } |
| 261 | public function __toString() |
| 262 | { |
| 263 | return $this->generateSelectClause([]); |
| 264 | } |
| 265 | } |
| 266 |