From 66efee82cb94336c4e3873b02bbaa6b9e288ca88 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Mon, 24 Jun 2024 18:53:30 +0200 Subject: [PATCH] Remove more array access deprecations --- phpstan-baseline.neon | 4 - psalm-baseline.xml | 7 - src/AuditReader.php | 111 ++++++----- src/Collection/AuditedCollection.php | 8 +- ...angedManyToManyEntityRevisionToPersist.php | 15 +- src/EventListener/CreateSchemaListener.php | 9 +- src/EventListener/LogRevisionsListener.php | 81 +++----- src/Utils/ORMCompatibilityTrait.php | 178 ++++++++++++++++-- 8 files changed, 261 insertions(+), 152 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 21e083c1..394c5050 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -3,7 +3,3 @@ parameters: # The class "AuditController" is deprecated and extends a class that is only supported in "symfony/http-foundation" < 5. # NEXT_MAJOR: Remove these files - src/Controller/AuditController.php - ignoreErrors: - # For compatibility with doctrine/orm 2 and 3 - - '#.+ has invalid type Doctrine\\ORM\\Mapping\\AssociationMapping\.$#' - - '#^Property SimpleThings\\EntityAudit\\Collection\\AuditedCollection\:\:\$associationDefinition has unknown class Doctrine\\ORM\\Mapping\\AssociationMapping as its type\.$#' diff --git a/psalm-baseline.xml b/psalm-baseline.xml index efe38aa5..ee3489dc 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -6,11 +6,4 @@ Controller - - - - |AssociationMapping]]> - |AssociationMapping]]> - - diff --git a/src/AuditReader.php b/src/AuditReader.php index 943c21c4..57ea5aaa 100644 --- a/src/AuditReader.php +++ b/src/AuditReader.php @@ -19,9 +19,10 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Exception\ORMException; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\QuoteStrategy; -use Doctrine\ORM\ORMException; +use Doctrine\ORM\ORMException as ORM2Exception; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Persisters\Entity\EntityPersister; use SimpleThings\EntityAudit\Collection\AuditedCollection; @@ -189,12 +190,17 @@ public function clearEntityCache(): void * @throws NotAuditedException * @throws Exception * @throws ORMException + * @throws ORM2Exception * @throws \RuntimeException * * @return object|null * + * @psalm-suppress UndefinedDocblockClass + * * @phpstan-param class-string $className * @phpstan-return T|null + * + * @phpstan-ignore throws.notThrowable */ public function find($className, $id, $revision, array $options = []) { @@ -215,7 +221,7 @@ public function find($className, $id, $revision, array $options = []) $idKeys = array_keys($id); $columnName = $idKeys[0]; } elseif (isset($classMetadata->fieldMappings[$idField])) { - $columnName = self::getMappingValue($classMetadata->fieldMappings[$idField], 'columnName'); + $columnName = self::getMappingColumnNameValue($classMetadata->fieldMappings[$idField]); } elseif (isset($classMetadata->associationMappings[$idField]['joinColumns'])) { $columnName = $classMetadata->associationMappings[$idField]['joinColumns'][0]['name']; } else { @@ -252,18 +258,15 @@ public function find($className, $id, $revision, array $options = []) } foreach ($classMetadata->associationMappings as $assoc) { - if ( - ($assoc['type'] & ClassMetadata::TO_ONE) === 0 - || false === $assoc['isOwningSide'] - || !isset($assoc['joinColumnFieldNames']) - ) { + if (!self::isToOneOwningSide($assoc)) { continue; } - foreach ($assoc['joinColumnFieldNames'] as $sourceCol) { + /** @var string $sourceCol */ + foreach (self::getMappingValue($assoc, 'joinColumnFieldNames') as $sourceCol) { $tableAlias = $classMetadata->isInheritanceTypeJoined() - && $classMetadata->isInheritedAssociation($assoc['fieldName']) - && !$classMetadata->isIdentifier($assoc['fieldName']) + && $classMetadata->isInheritedAssociation(self::getMappingFieldNameValue($assoc)) + && !$classMetadata->isIdentifier(self::getMappingFieldNameValue($assoc)) ? 're' // root entity : 'e'; $columnList[] = $tableAlias.'.'.$sourceCol; @@ -288,7 +291,7 @@ public function find($className, $id, $revision, array $options = []) !$classMetadata->isInheritanceTypeNone() && null !== $classMetadata->discriminatorColumn ) { - $columnList[] = self::getMappingValue($classMetadata->discriminatorColumn, 'name'); + $columnList[] = self::getMappingNameValue($classMetadata->discriminatorColumn); if ($classMetadata->isInheritanceTypeSingleTable() && null !== $classMetadata->discriminatorValue) { // Support for single table inheritance sub-classes @@ -300,7 +303,7 @@ public function find($className, $id, $revision, array $options = []) $whereSQL .= sprintf( ' AND %s IN (%s)', - self::getMappingValue($classMetadata->discriminatorColumn, 'name'), + self::getMappingNameValue($classMetadata->discriminatorColumn), implode(', ', $queriedDiscrValues) ); } @@ -386,10 +389,15 @@ public function findEntitesChangedAtRevision($revision) * @throws NotAuditedException * @throws Exception * @throws ORMException + * @throws ORM2Exception * @throws \RuntimeException * @throws DeletedException * * @return ChangedEntity[] + * + * @psalm-suppress UndefinedDocblockClass + * + * @phpstan-ignore throws.notThrowable */ public function findEntitiesChangedAtRevision($revision) { @@ -426,12 +434,8 @@ public function findEntitiesChangedAtRevision($revision) } foreach ($classMetadata->associationMappings as $assoc) { - if ( - ($assoc['type'] & ClassMetadata::TO_ONE) > 0 - && true === $assoc['isOwningSide'] - && isset($assoc['targetToSourceKeyColumns']) - ) { - foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) { + if (self::isToOneOwningSide($assoc)) { + foreach (self::getTargetToSourceKeyColumns($assoc) as $sourceCol) { $columnList .= ', '.$sourceCol; $columnMap[$sourceCol] = $this->getSQLResultCasing($this->platform, $sourceCol); } @@ -443,15 +447,15 @@ public function findEntitiesChangedAtRevision($revision) $classMetadata->isInheritanceTypeSingleTable() && null !== $classMetadata->discriminatorColumn ) { - $columnList .= ', e.'.self::getMappingValue($classMetadata->discriminatorColumn, 'name'); - $whereSQL .= ' AND e.'.self::getMappingValue($classMetadata->discriminatorColumn, 'fieldName').' = ?'; + $columnList .= ', e.'.self::getMappingNameValue($classMetadata->discriminatorColumn); + $whereSQL .= ' AND e.'.self::getMappingFieldNameValue($classMetadata->discriminatorColumn).' = ?'; $params[] = $classMetadata->discriminatorValue; } elseif ( $classMetadata->isInheritanceTypeJoined() && $classMetadata->rootEntityName !== $classMetadata->name && null !== $classMetadata->discriminatorColumn ) { - $columnList .= ', re.'.self::getMappingValue($classMetadata->discriminatorColumn, 'name'); + $columnList .= ', re.'.self::getMappingNameValue($classMetadata->discriminatorColumn); $rootClass = $this->em->getClassMetadata($classMetadata->rootEntityName); $rootTableName = $this->config->getTableName($rootClass); @@ -545,7 +549,7 @@ public function findRevisions($className, $id) if ('' !== $whereSQL) { $whereSQL .= ' AND '; } - $whereSQL .= 'e.'.self::getMappingValue($classMetadata->fieldMappings[$idField], 'columnName').' = ?'; + $whereSQL .= 'e.'.self::getMappingColumnNameValue($classMetadata->fieldMappings[$idField]).' = ?'; } elseif (isset($classMetadata->associationMappings[$idField]['joinColumns'])) { if ('' !== $whereSQL) { $whereSQL .= ' AND '; @@ -607,12 +611,12 @@ public function getCurrentRevision($className, $id) if ('' !== $whereSQL) { $whereSQL .= ' AND '; } - $whereSQL .= 'e.'.self::getMappingValue($classMetadata->fieldMappings[$idField], 'columnName').' = ?'; + $whereSQL .= 'e.'.self::getMappingColumnNameValue($classMetadata->fieldMappings[$idField]).' = ?'; } elseif (isset($classMetadata->associationMappings[$idField]['joinColumns'])) { if ('' !== $whereSQL) { $whereSQL .= ' AND '; } - $whereSQL .= 'e.'.self::getMappingValue($classMetadata->associationMappings[$idField]['joinColumns'][0], 'name').' = ?'; + $whereSQL .= 'e.'.self::getMappingNameValue($classMetadata->associationMappings[$idField]['joinColumns'][0]).' = ?'; } } @@ -644,12 +648,17 @@ public function getCurrentRevision($className, $id) * @throws NotAuditedException * @throws Exception * @throws ORMException + * @throws ORM2Exception * @throws \RuntimeException * * @return array> * + * @psalm-suppress UndefinedDocblockClass + * * @phpstan-param class-string $className * @phpstan-return array + * + * @phpstan-ignore throws.notThrowable */ public function diff($className, $id, $oldRevision, $newRevision) { @@ -697,12 +706,17 @@ public function getEntityValues($className, $entity) * @throws NotAuditedException * @throws Exception * @throws ORMException + * @throws ORM2Exception * @throws DeletedException * * @return array * + * @psalm-suppress UndefinedDocblockClass + * * @phpstan-param class-string $className * @phpstan-return array + * + * @phpstan-ignore throws.notThrowable */ public function getEntityHistory($className, $id) { @@ -722,11 +736,9 @@ public function getEntityHistory($className, $id) $whereId = []; foreach ($classMetadata->identifier as $idField) { if (isset($classMetadata->fieldMappings[$idField])) { - /** @phpstan-var literal-string $columnName */ - $columnName = self::getMappingValue($classMetadata->fieldMappings[$idField], 'columnName'); + $columnName = self::getMappingColumnNameValue($classMetadata->fieldMappings[$idField]); } elseif (isset($classMetadata->associationMappings[$idField]['joinColumns'])) { - /** @phpstan-var literal-string $columnName */ - $columnName = self::getMappingValue($classMetadata->associationMappings[$idField]['joinColumns'][0], 'name'); + $columnName = self::getMappingNameValue($classMetadata->associationMappings[$idField]['joinColumns'][0]); } else { continue; } @@ -752,16 +764,11 @@ public function getEntityHistory($className, $id) } foreach ($classMetadata->associationMappings as $assoc) { - if ( - ($assoc['type'] & ClassMetadata::TO_ONE) === 0 - || false === $assoc['isOwningSide'] - || !isset($assoc['targetToSourceKeyColumns']) - ) { + if (!self::isToOneOwningSide($assoc)) { continue; } - /** @phpstan-var literal-string $sourceCol */ - foreach ($assoc['targetToSourceKeyColumns'] as $sourceCol) { + foreach (self::getTargetToSourceKeyColumns($assoc) as $sourceCol) { $columnList[] = $sourceCol; $columnMap[$sourceCol] = $this->getSQLResultCasing($this->platform, $sourceCol); } @@ -816,12 +823,17 @@ protected function getEntityPersister($className) * @throws NotAuditedException * @throws Exception * @throws ORMException + * @throws ORM2Exception * @throws \RuntimeException * * @return object * + * @psalm-suppress UndefinedDocblockClass + * * @phpstan-param class-string $className * @phpstan-return T + * + * @phpstan-ignore throws.notThrowable */ private function createEntity($className, array $columnMap, array $data, $revision) { @@ -847,7 +859,7 @@ private function createEntity($className, array $columnMap, array $data, $revisi !$classMetadata->isInheritanceTypeNone() && null !== $classMetadata->discriminatorColumn ) { - $discriminator = $data[self::getMappingValue($classMetadata->discriminatorColumn, 'name')]; + $discriminator = $data[self::getMappingNameValue($classMetadata->discriminatorColumn)]; if (!isset($classMetadata->discriminatorMap[$discriminator])) { throw new \RuntimeException("No mapping found for [{$discriminator}]."); } @@ -894,12 +906,12 @@ private function createEntity($className, array $columnMap, array $data, $revisi foreach ($classMetadata->associationMappings as $field => $assoc) { /** @phpstan-var class-string $targetEntity */ - $targetEntity = $assoc['targetEntity']; + $targetEntity = self::getMappingTargetEntityValue($assoc); $targetClass = $this->em->getClassMetadata($targetEntity); $mappedBy = $assoc['mappedBy'] ?? null; - if (0 !== ($assoc['type'] & ClassMetadata::TO_ONE)) { + if (self::isToOne($assoc)) { if ($this->metadataFactory->isAudited($targetEntity)) { if ($this->loadAuditedEntities) { // Primary Key. Used for audit tables queries. @@ -907,8 +919,8 @@ private function createEntity($className, array $columnMap, array $data, $revisi // Primary Field. Used when fallback to Doctrine finder. $pf = []; - if (true === $assoc['isOwningSide'] && isset($assoc['targetToSourceKeyColumns'])) { - foreach ($assoc['targetToSourceKeyColumns'] as $foreign => $local) { + if (self::isToOneOwningSide($assoc)) { + foreach (self::getTargetToSourceKeyColumns($assoc) as $foreign => $local) { $key = $data[$columnMap[$local]]; if (null === $key) { continue; @@ -921,15 +933,15 @@ private function createEntity($className, array $columnMap, array $data, $revisi $otherEntityAssoc = $this->em->getClassMetadata($targetEntity) ->associationMappings[$mappedBy]; - if (isset($otherEntityAssoc['targetToSourceKeyColumns'])) { - foreach ($otherEntityAssoc['targetToSourceKeyColumns'] as $local => $foreign) { + if (self::isToOneOwningSide($otherEntityAssoc)) { + foreach (self::getTargetToSourceKeyColumns($otherEntityAssoc) as $local => $foreign) { $key = $data[$classMetadata->getFieldName($local)]; if (null === $key) { continue; } $pk[$foreign] = $key; - $pf[$otherEntityAssoc['fieldName']] = $key; + $pf[self::getMappingFieldNameValue($otherEntityAssoc)] = $key; } } } @@ -956,9 +968,9 @@ private function createEntity($className, array $columnMap, array $data, $revisi } } else { if ($this->loadNativeEntities) { - if (true === $assoc['isOwningSide'] && isset($assoc['targetToSourceKeyColumns'])) { + if (self::isToOneOwningSide($assoc)) { $associatedId = []; - foreach ($assoc['targetToSourceKeyColumns'] as $targetColumn => $srcColumn) { + foreach (self::getTargetToSourceKeyColumns($assoc) as $targetColumn => $srcColumn) { $joinColumnValue = $data[$columnMap[$srcColumn]] ?? null; if (null !== $joinColumnValue) { $targetField = $targetClass->fieldNames[$targetColumn]; @@ -1033,7 +1045,7 @@ private function createEntity($className, array $columnMap, array $data, $revisi if (self::isManyToManyOwningSideMapping($assoc)) { $whereId = [$this->config->getRevisionFieldName().' = ?']; $values = [$revision]; - foreach (self::getMappingValue($assoc, 'relationToSourceKeyColumns') as $sourceKeyJoinColumn => $sourceKeyColumn) { + foreach (self::getRelationToSourceKeyColumns($assoc) as $sourceKeyJoinColumn => $sourceKeyColumn) { $whereId[] = "{$sourceKeyJoinColumn} = ?"; $reflField = $classMetadata->reflFields['id']; @@ -1048,10 +1060,10 @@ private function createEntity($className, array $columnMap, array $data, $revisi $this->config->getRevisionTypeFieldName(), ]; $tableName = $this->config->getTablePrefix() - .self::getJoinTableName($assoc) + .self::getMappingJoinTableNameValue($assoc) .$this->config->getTableSuffix(); - foreach (self::getMappingValue($assoc, 'relationToTargetKeyColumns') as $targetKeyJoinColumn => $targetKeyColumn) { + foreach (self::getRelationToTargetKeyColumns($assoc) as $targetKeyJoinColumn => $targetKeyColumn) { $columnList[] = $targetKeyJoinColumn; } @@ -1072,8 +1084,7 @@ private function createEntity($className, array $columnMap, array $data, $revisi foreach ($rows as $row) { $id = []; - /** @phpstan-var string $targetKeyColumn */ - foreach (self::getMappingValue($assoc, 'relationToTargetKeyColumns') as $targetKeyJoinColumn => $targetKeyColumn) { + foreach (self::getRelationToTargetKeyColumns($assoc) as $targetKeyJoinColumn => $targetKeyColumn) { $joinKey = $row[$targetKeyJoinColumn]; $id[$targetKeyColumn] = $joinKey; } diff --git a/src/Collection/AuditedCollection.php b/src/Collection/AuditedCollection.php index 55152d56..063e81ea 100644 --- a/src/Collection/AuditedCollection.php +++ b/src/Collection/AuditedCollection.php @@ -59,10 +59,10 @@ class AuditedCollection implements Collection protected $initialized = false; /** - * @param string $class - * @param array $associationDefinition - * @param array $foreignKeys - * @param string|int $revision + * @param string $class + * @param array|AssociationMapping $associationDefinition + * @param array $foreignKeys + * @param string|int $revision * * @phpstan-param class-string $class * @phpstan-param ClassMetadata $metadata diff --git a/src/DeferredChangedManyToManyEntityRevisionToPersist.php b/src/DeferredChangedManyToManyEntityRevisionToPersist.php index 05182066..2b6f3448 100644 --- a/src/DeferredChangedManyToManyEntityRevisionToPersist.php +++ b/src/DeferredChangedManyToManyEntityRevisionToPersist.php @@ -14,6 +14,7 @@ namespace SimpleThings\EntityAudit; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\ManyToManyOwningSideMapping; /** * @internal @@ -21,16 +22,16 @@ final class DeferredChangedManyToManyEntityRevisionToPersist { /** - * @param array $assoc - * @param array $entityData - * @param ClassMetadata $class - * @param ClassMetadata $targetClass + * @param array|ManyToManyOwningSideMapping $assoc + * @param array $entityData + * @param ClassMetadata $class + * @param ClassMetadata $targetClass */ public function __construct( private object $entity, private string $revType, private array $entityData, - private array $assoc, + private array|ManyToManyOwningSideMapping $assoc, private ClassMetadata $class, private ClassMetadata $targetClass ) { @@ -55,9 +56,9 @@ public function getEntityData(): array } /** - * @return array + * @return array|ManyToManyOwningSideMapping */ - public function getAssoc(): array + public function getAssoc(): array|ManyToManyOwningSideMapping { return $this->assoc; } diff --git a/src/EventListener/CreateSchemaListener.php b/src/EventListener/CreateSchemaListener.php index 5dcb37e2..0b06057a 100644 --- a/src/EventListener/CreateSchemaListener.php +++ b/src/EventListener/CreateSchemaListener.php @@ -64,6 +64,9 @@ public function getSubscribedEvents() ]; } + /** + * @psalm-suppress TypeDoesNotContainType, NoValue + */ public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs): void { $cm = $eventArgs->getClassMetadata(); @@ -112,10 +115,10 @@ public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs) foreach ($cm->associationMappings as $associationMapping) { if (self::isManyToManyOwningSideMapping($associationMapping)) { - if ($schema->hasTable(self::getJoinTableName($associationMapping))) { - $this->createRevisionJoinTableForJoinTable($schema, self::getJoinTableName($associationMapping)); + if ($schema->hasTable(self::getMappingJoinTableNameValue($associationMapping))) { + $this->createRevisionJoinTableForJoinTable($schema, self::getMappingJoinTableNameValue($associationMapping)); } else { - $this->defferedJoinTablesToCreate[] = self::getJoinTableName($associationMapping); + $this->defferedJoinTablesToCreate[] = self::getMappingJoinTableNameValue($associationMapping); } } } diff --git a/src/EventListener/LogRevisionsListener.php b/src/EventListener/LogRevisionsListener.php index 1308ba4b..af4d3c40 100644 --- a/src/EventListener/LogRevisionsListener.php +++ b/src/EventListener/LogRevisionsListener.php @@ -157,10 +157,8 @@ public function postFlush(PostFlushEventArgs $eventArgs): void foreach ($meta->associationMappings as $mapping) { if (isset($mapping['joinColumns'])) { foreach ($mapping['joinColumns'] as $definition) { - if (self::getMappingValue($definition, 'name') === $column) { - /** @var class-string $targetEntity */ - $targetEntity = $mapping['targetEntity']; - $targetTable = $em->getClassMetadata($targetEntity); + if (self::getMappingNameValue($definition) === $column) { + $targetTable = $em->getClassMetadata(self::getMappingTargetEntityValue($mapping)); $type = $targetTable->getTypeOfField($targetTable->getFieldForColumn(self::getMappingValue($definition, 'referencedColumnName'))); } } @@ -181,12 +179,10 @@ public function postFlush(PostFlushEventArgs $eventArgs): void foreach ($meta->identifier as $idField) { if (isset($meta->fieldMappings[$idField])) { - /** @phpstan-var literal-string $columnName */ - $columnName = self::getMappingValue($meta->fieldMappings[$idField], 'columnName'); + $columnName = self::getMappingColumnNameValue($meta->fieldMappings[$idField]); $types[] = self::getMappingValue($meta->fieldMappings[$idField], 'type'); } elseif (isset($meta->associationMappings[$idField]['joinColumns'])) { - /** @phpstan-var literal-string $columnName */ - $columnName = self::getMappingValue($meta->associationMappings[$idField]['joinColumns'][0], 'name'); + $columnName = self::getMappingNameValue($meta->associationMappings[$idField]['joinColumns'][0]); $types[] = $meta->associationMappings[$idField]['type']; } else { throw new \RuntimeException('column name not found for'.$idField); @@ -400,8 +396,6 @@ private function getRevisionId(Connection $conn) * @throws Exception * * @return literal-string - * - * @psalm-suppress MoreSpecificReturnType,PropertyTypeCoercion,LessSpecificReturnStatement https://github.com/vimeo/psalm/issues/10909 */ private function getInsertRevisionSQL(EntityManagerInterface $em, ClassMetadata $class): string { @@ -420,8 +414,7 @@ private function getInsertRevisionSQL(EntityManagerInterface $em, ClassMetadata } if (self::isToOneOwningSide($assoc)) { - /** @phpstan-var literal-string $sourceCol */ - foreach (self::getMappingValue($assoc, 'targetToSourceKeyColumns') as $sourceCol) { + foreach (self::getTargetToSourceKeyColumns($assoc) as $sourceCol) { $fields[$sourceCol] = true; $sql .= ', '.$sourceCol; $placeholders[] = '?'; @@ -460,8 +453,7 @@ private function getInsertRevisionSQL(EntityManagerInterface $em, ClassMetadata ) && null !== $class->discriminatorColumn ) { - /** @var literal-string $discriminatorColumnName */ - $discriminatorColumnName = self::getMappingValue($class->discriminatorColumn, 'name'); + $discriminatorColumnName = self::getMappingNameValue($class->discriminatorColumn); $sql .= ', '.$discriminatorColumnName; $placeholders[] = '?'; } @@ -480,16 +472,13 @@ private function getInsertRevisionSQL(EntityManagerInterface $em, ClassMetadata * @param array|ManyToManyOwningSideMapping $assoc * * @return literal-string - * - * @psalm-suppress MoreSpecificReturnType,PropertyTypeCoercion,LessSpecificReturnStatement https://github.com/vimeo/psalm/issues/10909 */ private function getInsertJoinTableRevisionSQL( ClassMetadata $class, ClassMetadata $targetClass, - /* @phpstan-ignore-next-line */ array|ManyToManyOwningSideMapping $assoc ): string { - $joinTableName = self::getJoinTableName($assoc); + $joinTableName = self::getMappingJoinTableNameValue($assoc); $cacheKey = $class->name.'.'.$targetClass->name.'.'.$joinTableName; if ( @@ -499,27 +488,16 @@ private function getInsertJoinTableRevisionSQL( $tableName = $this->config->getTablePrefix().$joinTableName.$this->config->getTableSuffix(); - /** @psalm-trace $sql */ $sql = 'INSERT INTO '.$tableName .' ('.$this->config->getRevisionFieldName(). ', '.$this->config->getRevisionTypeFieldName(); - /** - * @phpstan-var literal-string $sourceColumn - * - * @phpstan-ignore argument.type - */ - foreach (self::getMappingValue($assoc, 'relationToSourceKeyColumns') as $sourceColumn => $targetColumn) { + foreach (self::getRelationToSourceKeyColumns($assoc) as $sourceColumn => $targetColumn) { $sql .= ', '.$sourceColumn; $placeholders[] = '?'; } - /** - * @phpstan-var literal-string $sourceColumn - * - * @phpstan-ignore argument.type - */ - foreach (self::getMappingValue($assoc, 'relationToTargetKeyColumns') as $sourceColumn => $targetColumn) { + foreach (self::getRelationToTargetKeyColumns($assoc) as $sourceColumn => $targetColumn) { $sql .= ', '.$sourceColumn; $placeholders[] = '?'; } @@ -551,9 +529,8 @@ private function saveRevisionEntityData(EntityManagerInterface $em, ClassMetadat continue; } - if ($assoc['isOwningSide']) { - if (0 !== ($assoc['type'] & ClassMetadata::TO_ONE) - && isset($assoc['sourceToTargetKeyColumns'])) { + if (self::isOwningSide($assoc)) { + if (self::isToOneOwningSide($assoc)) { $data = $entityData[$field] ?? null; $relatedId = []; @@ -561,11 +538,9 @@ private function saveRevisionEntityData(EntityManagerInterface $em, ClassMetadat $relatedId = $uow->getEntityIdentifier($data); } - /** @var class-string $targetEntity */ - $targetEntity = $assoc['targetEntity']; - $targetClass = $em->getClassMetadata($targetEntity); + $targetClass = $em->getClassMetadata(self::getMappingTargetEntityValue($assoc)); - foreach ($assoc['sourceToTargetKeyColumns'] as $sourceColumn => $targetColumn) { + foreach (self::getSourceToTargetKeyColumns($assoc) as $sourceColumn => $targetColumn) { $fields[$sourceColumn] = true; if (null === $data) { $params[] = null; @@ -575,9 +550,8 @@ private function saveRevisionEntityData(EntityManagerInterface $em, ClassMetadat $types[] = $targetClass->getTypeOfField($targetClass->getFieldForColumn($targetColumn)); } } - } elseif (($assoc['type'] & ClassMetadata::MANY_TO_MANY) > 0 - && isset($assoc['relationToSourceKeyColumns'], $assoc['relationToTargetKeyColumns'])) { - $targetClass = $em->getClassMetadata($assoc['targetEntity']); + } elseif (self::isManyToManyOwningSideMapping($assoc)) { + $targetClass = $em->getClassMetadata(self::getMappingTargetEntityValue($assoc)); $collection = $entityData[$assoc['fieldName']]; if (null !== $collection) { @@ -622,7 +596,7 @@ private function saveRevisionEntityData(EntityManagerInterface $em, ClassMetadat && $class->name === $class->rootEntityName && null !== $class->discriminatorColumn ) { - $params[] = $entityData[self::getMappingValue($class->discriminatorColumn, 'name')]; + $params[] = $entityData[self::getMappingNameValue($class->discriminatorColumn)]; $types[] = self::getMappingValue($class->discriminatorColumn, 'type'); } @@ -630,11 +604,10 @@ private function saveRevisionEntityData(EntityManagerInterface $em, ClassMetadat $class->isInheritanceTypeJoined() && $class->name !== $class->rootEntityName && null !== $class->discriminatorColumn ) { - $entityData[self::getMappingValue($class->discriminatorColumn, 'name')] = $class->discriminatorValue; + $entityData[self::getMappingNameValue($class->discriminatorColumn)] = $class->discriminatorValue; $this->saveRevisionEntityData( $em, $em->getClassMetadata($class->rootEntityName), - /* @phpstan-ignore argument.type */ $entityData, $revType ); @@ -660,7 +633,6 @@ private function recordRevisionForManyToManyEntity( EntityManagerInterface $em, string $revType, array $entityData, - /* @phpstan-ignore-next-line */ array|ManyToManyOwningSideMapping $assoc, ClassMetadata $class, ClassMetadata $targetClass @@ -669,14 +641,12 @@ private function recordRevisionForManyToManyEntity( $joinTableParams = [$this->getRevisionId($conn), $revType]; $joinTableTypes = [\PDO::PARAM_INT, \PDO::PARAM_STR]; - /* @phpstan-ignore argument.type */ - foreach (self::getMappingValue($assoc, 'relationToSourceKeyColumns') as $targetColumn) { + foreach (self::getRelationToSourceKeyColumns($assoc) as $targetColumn) { $joinTableParams[] = $entityData[$class->fieldNames[$targetColumn]]; $joinTableTypes[] = PersisterHelper::getTypeOfColumn($targetColumn, $class, $em); } - /* @phpstan-ignore argument.type */ - foreach (self::getMappingValue($assoc, 'relationToTargetKeyColumns') as $targetColumn) { + foreach (self::getRelationToTargetKeyColumns($assoc) as $targetColumn) { $reflField = $targetClass->reflFields[$targetClass->fieldNames[$targetColumn]]; \assert(null !== $reflField); $joinTableParams[] = $reflField->getValue($relatedEntity); @@ -740,7 +710,7 @@ private function prepareUpdateData(EntityManagerInterface $em, EntityPersister $ $newVal = $change[1]; if (!isset($classMetadata->associationMappings[$field])) { - $columnName = self::getMappingValue($classMetadata->fieldMappings[$field], 'columnName'); + $columnName = self::getMappingColumnNameValue($classMetadata->fieldMappings[$field]); $result[$persister->getOwningTable($field)][$columnName] = $newVal; continue; @@ -749,10 +719,7 @@ private function prepareUpdateData(EntityManagerInterface $em, EntityPersister $ $assoc = $classMetadata->associationMappings[$field]; // Only owning side of x-1 associations can have a FK column. - if ( - 0 === ($assoc['type'] & ClassMetadata::TO_ONE) - || false === $assoc['isOwningSide'] - || !isset($assoc['joinColumns'])) { + if (!self::isToOneOwningSide($assoc)) { continue; } @@ -772,13 +739,11 @@ private function prepareUpdateData(EntityManagerInterface $em, EntityPersister $ $newValId = $uow->getEntityIdentifier($newVal); } - /** @var class-string $targetEntity */ - $targetEntity = $assoc['targetEntity']; - $targetClass = $em->getClassMetadata($targetEntity); + $targetClass = $em->getClassMetadata(self::getMappingTargetEntityValue($assoc)); $owningTable = $persister->getOwningTable($field); foreach ($assoc['joinColumns'] as $joinColumn) { - $sourceColumn = self::getMappingValue($joinColumn, 'name'); + $sourceColumn = self::getMappingNameValue($joinColumn); $targetColumn = self::getMappingValue($joinColumn, 'referencedColumnName'); $result[$owningTable][$sourceColumn] = null !== $newValId diff --git a/src/Utils/ORMCompatibilityTrait.php b/src/Utils/ORMCompatibilityTrait.php index b770a403..f117b30c 100644 --- a/src/Utils/ORMCompatibilityTrait.php +++ b/src/Utils/ORMCompatibilityTrait.php @@ -29,12 +29,9 @@ trait ORMCompatibilityTrait { /** * @param array|AssociationMapping|EmbeddedClassMapping|FieldMapping|JoinColumnMapping|DiscriminatorColumnMapping $mapping - * - * @phpstan-ignore-next-line */ - private static function getMappingValue(array|AssociationMapping|EmbeddedClassMapping|FieldMapping|JoinColumnMapping|DiscriminatorColumnMapping $mapping, string $key): mixed + final protected static function getMappingValue(array|AssociationMapping|EmbeddedClassMapping|FieldMapping|JoinColumnMapping|DiscriminatorColumnMapping $mapping, string $key): mixed { - /* @phpstan-ignore-next-line */ if ($mapping instanceof AssociationMapping || $mapping instanceof EmbeddedClassMapping || $mapping instanceof FieldMapping || $mapping instanceof JoinColumnMapping || $mapping instanceof DiscriminatorColumnMapping) { /* @phpstan-ignore property.dynamicName */ return $mapping->$key; @@ -44,52 +41,195 @@ private static function getMappingValue(array|AssociationMapping|EmbeddedClassMa } /** - * @param array|ManyToManyOwningSideMapping $mapping + * @param array|AssociationMapping|FieldMapping|DiscriminatorColumnMapping $mapping + * + * @return literal-string + */ + final protected static function getMappingFieldNameValue(array|AssociationMapping|EmbeddedClassMapping|FieldMapping|DiscriminatorColumnMapping $mapping): string + { + if ($mapping instanceof AssociationMapping || $mapping instanceof FieldMapping || $mapping instanceof DiscriminatorColumnMapping) { + /* @phpstan-ignore return.type */ + return $mapping->fieldName; + } + + /* @phpstan-ignore return.type */ + return $mapping['fieldName']; + } + + /** + * @param array|JoinColumnMapping|DiscriminatorColumnMapping $mapping + * + * @return literal-string + */ + final protected static function getMappingNameValue(array|JoinColumnMapping|DiscriminatorColumnMapping $mapping): string + { + if ($mapping instanceof JoinColumnMapping || $mapping instanceof DiscriminatorColumnMapping) { + /* @phpstan-ignore return.type */ + return $mapping->name; + } + + /* @phpstan-ignore return.type */ + return $mapping['name']; + } + + /** + * @param array|FieldMapping $mapping * * @return literal-string + */ + final protected static function getMappingColumnNameValue(array|FieldMapping $mapping): string + { + if ($mapping instanceof FieldMapping) { + /* @phpstan-ignore return.type */ + return $mapping->columnName; + } + + /* @phpstan-ignore return.type */ + return $mapping['columnName']; + } + + /** + * @param array|ManyToManyOwningSideMapping $mapping * - * @phpstan-ignore-next-line + * @return literal-string */ - private static function getJoinTableName(array|ManyToManyOwningSideMapping $mapping): string + final protected static function getMappingJoinTableNameValue(array|ManyToManyOwningSideMapping $mapping): string { - /* @phpstan-ignore-next-line */ if ($mapping instanceof ManyToManyOwningSideMapping) { - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore return.type */ return $mapping->joinTable->name; } - /* @phpstan-ignore-next-line */ + /* @phpstan-ignore return.type */ return $mapping['joinTable']['name']; } /** * @param array|AssociationMapping $mapping + * + * @phpstan-assert-if-true ManyToManyOwningSideMapping $mapping */ - private static function isManyToManyOwningSideMapping(array|AssociationMapping $mapping): bool + final protected static function isManyToManyOwningSideMapping(array|AssociationMapping $mapping): bool { - /* @phpstan-ignore-next-line */ if ($mapping instanceof AssociationMapping) { - /* @phpstan-ignore-next-line */ return $mapping instanceof ManyToManyOwningSideMapping; } - /* @phpstan-ignore-next-line */ - return $mapping['isOwningSide'] && isset($mapping['joinTable']['name']); + return isset($mapping['joinTable']['name'], $mapping['relationToSourceKeyColumns'], $mapping['relationToTargetKeyColumns']) + && true === $mapping['isOwningSide'] + && ($mapping['type'] & ClassMetadata::MANY_TO_MANY) > 0; } /** * @param array|AssociationMapping $mapping + * + * @phpstan-assert-if-true ToOneOwningSideMapping $mapping */ - private static function isToOneOwningSide(array|AssociationMapping $mapping): bool + final protected static function isToOneOwningSide(array|AssociationMapping $mapping): bool { - /* @phpstan-ignore class.notFound */ if ($mapping instanceof AssociationMapping) { - /* @phpstan-ignore class.notFound */ - return $mapping instanceof ToOneOwningSideMapping; + return $mapping->isToOneOwningSide(); } return ($mapping['type'] & ClassMetadata::TO_ONE) > 0 && true === $mapping['isOwningSide'] && isset($mapping['targetToSourceKeyColumns']); } + + /** + * @param array|AssociationMapping $mapping + */ + final protected static function isToOne(array|AssociationMapping $mapping): bool + { + if ($mapping instanceof AssociationMapping) { + return $mapping->isToOne(); + } + + return ($mapping['type'] & ClassMetadata::TO_ONE) > 0; + } + + /** + * @param array|ToOneOwningSideMapping $mapping + * + * @return array + */ + final protected static function getTargetToSourceKeyColumns(array|ToOneOwningSideMapping $mapping): array + { + if ($mapping instanceof ToOneOwningSideMapping) { + /* @phpstan-ignore return.type */ + return $mapping->targetToSourceKeyColumns; + } + + return $mapping['targetToSourceKeyColumns']; + } + + /** + * @param array|ToOneOwningSideMapping $mapping + * + * @return array + */ + final protected static function getSourceToTargetKeyColumns(array|ToOneOwningSideMapping $mapping): array + { + if ($mapping instanceof ToOneOwningSideMapping) { + return $mapping->sourceToTargetKeyColumns; + } + + return $mapping['sourceToTargetKeyColumns']; + } + + /** + * @param array|ManyToManyOwningSideMapping $mapping + * + * @return array + */ + final protected static function getRelationToSourceKeyColumns(array|ManyToManyOwningSideMapping $mapping): array + { + if ($mapping instanceof ManyToManyOwningSideMapping) { + /* @phpstan-ignore return.type */ + return $mapping->relationToSourceKeyColumns; + } + + return $mapping['relationToSourceKeyColumns']; + } + + /** + * @param array|ManyToManyOwningSideMapping $mapping + * + * @return array + */ + final protected static function getRelationToTargetKeyColumns(array|ManyToManyOwningSideMapping $mapping): array + { + if ($mapping instanceof ManyToManyOwningSideMapping) { + /* @phpstan-ignore return.type */ + return $mapping->relationToTargetKeyColumns; + } + + return $mapping['relationToTargetKeyColumns']; + } + + /** + * @param array|AssociationMapping $mapping + * + * @phpstan-return class-string + */ + final protected static function getMappingTargetEntityValue(array|AssociationMapping $mapping): string + { + if ($mapping instanceof AssociationMapping) { + return $mapping->targetEntity; + } + + return $mapping['targetEntity']; + } + + /** + * @param array|AssociationMapping $mapping + */ + final protected static function isOwningSide(array|AssociationMapping $mapping): bool + { + if ($mapping instanceof AssociationMapping) { + return $mapping->isOwningSide(); + } + + return true === $mapping['isOwningSide']; + } }