Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
namespace Doctrine\ORM;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\TypeRegistry;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\Cache\CacheConfiguration;
use Doctrine\ORM\Exception\InvalidEntityRepository;
Expand All @@ -29,6 +31,7 @@

use function class_exists;
use function is_a;
use function method_exists;
use function strtolower;

use const PHP_VERSION_ID;
Expand Down Expand Up @@ -723,4 +726,19 @@
{
return $this->attributes['fetchModeSubselectBatchSize'] ?? 100;
}

/**
* Returns the type registry for this configuration.
* Falls back to the global type registry when running against DBAL < 4.5,
* which does not have {@see \Doctrine\DBAL\Configuration::getTypeRegistry()}.
*/
public function getTypeRegistry(): TypeRegistry
{
// @phpstan-ignore function.alreadyNarrowedType (method_exists check is for DBAL v3 compatibility)
if (method_exists(parent::class, 'getTypeRegistry')) {

Check failure on line 738 in src/Configuration.php

View workflow job for this annotation

GitHub Actions / Static Analysis with PHPStan (default, phpstan.neon)

No error with identifier function.alreadyNarrowedType is reported on line 738.
return parent::getTypeRegistry();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering whether this is a good idea. If the TypeRegistry belongs to the DBAL configuration, we should be reading it from the configuration object of the associated DBAL Connection, not from the ORM Configuration object.
There is no guarantee that the ORM Configuration is used to create the DBAL connection (even though it extends the DBAL Configuration class). Actually, DoctrineBundle configures DBAL and ORM separately, so it is actually guaranteed that they will not match in Symfony projects.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the same TypeRegistry will be injected into both by the DoctrineBundle (see doctrine/DoctrineBundle#2221), but having two configuration sources does indeed open the door to inconsistencies. So I'm going to remove Configuration::getTypeRegistry from the ORM and read it from the DBAL configuration instead. I'll use a helper function to fall back to the static method for DBAL versions earlier than 4.5.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the bundle wires the same type registry in the ORM config only because of this PR using a double source of truth. Using the DBAL config as single source of truth for the type registry allows to simplify the bundle PR.

}

return Type::getTypeRegistry();
}
}
15 changes: 10 additions & 5 deletions src/Internal/Hydration/AbstractHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ public function __construct(protected EntityManagerInterface $em)
$this->uow = $em->getUnitOfWork();
}

private function getType(string $name): Type
{
return $this->em->getConfiguration()->getTypeRegistry()->get($name);
}

/**
* Initiates a row-by-row hydration.
*
Expand Down Expand Up @@ -458,7 +463,7 @@ protected function hydrateColumnInfo(string $key): array|null
$columnInfo = [
'isIdentifier' => in_array($fieldName, $classMetadata->identifier, true),
'fieldName' => $fieldName,
'type' => Type::getType($fieldMapping->type),
'type' => $this->getType($fieldMapping->type),
'dqlAlias' => $ownerMap,
'enumType' => $this->rsm->enumMappings[$key] ?? null,
];
Expand Down Expand Up @@ -486,7 +491,7 @@ protected function hydrateColumnInfo(string $key): array|null
'isScalar' => true,
'isNewObjectParameter' => true,
'fieldName' => $this->rsm->scalarMappings[$key],
'type' => Type::getType($this->rsm->typeMappings[$key]),
'type' => $this->getType($this->rsm->typeMappings[$key]),
'argIndex' => $mapping['argIndex'],
'objIndex' => $mapping['objIndex'],
'enumType' => $this->rsm->enumMappings[$key] ?? null,
Expand All @@ -495,7 +500,7 @@ protected function hydrateColumnInfo(string $key): array|null
case isset($this->rsm->scalarMappings[$key], $this->hints[LimitSubqueryWalker::FORCE_DBAL_TYPE_CONVERSION]):
return $this->cache[$key] = [
'fieldName' => $this->rsm->scalarMappings[$key],
'type' => Type::getType($this->rsm->typeMappings[$key]),
'type' => $this->getType($this->rsm->typeMappings[$key]),
'dqlAlias' => '',
'enumType' => $this->rsm->enumMappings[$key] ?? null,
];
Expand All @@ -504,7 +509,7 @@ protected function hydrateColumnInfo(string $key): array|null
return $this->cache[$key] = [
'isScalar' => true,
'fieldName' => $this->rsm->scalarMappings[$key],
'type' => Type::getType($this->rsm->typeMappings[$key]),
'type' => $this->getType($this->rsm->typeMappings[$key]),
'enumType' => $this->rsm->enumMappings[$key] ?? null,
];

Expand All @@ -513,7 +518,7 @@ protected function hydrateColumnInfo(string $key): array|null
$fieldName = $this->rsm->metaMappings[$key];
$dqlAlias = $this->rsm->columnOwnerMap[$key];
$type = isset($this->rsm->typeMappings[$key])
? Type::getType($this->rsm->typeMappings[$key])
? $this->getType($this->rsm->typeMappings[$key])
: null;

// Cache metadata fetch
Expand Down
3 changes: 1 addition & 2 deletions src/Persisters/Collection/OneToManyPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use BadMethodCallException;
use Doctrine\Common\Collections\Criteria;
use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityNotFoundException;
use Doctrine\ORM\Mapping\MappingException;
use Doctrine\ORM\Mapping\OneToManyAssociationMapping;
Expand Down Expand Up @@ -224,7 +223,7 @@ private function deleteJoinedEntityCollection(PersistentCollection $collection):
$columnDefinitions[$idColumnName] = [
'name' => $idColumnName,
'notnull' => true,
'type' => Type::getType(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $this->em)),
'type' => $this->em->getConfiguration()->getTypeRegistry()->get(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $this->em)),
];
}

Expand Down
3 changes: 1 addition & 2 deletions src/Persisters/Entity/AbstractEntityInheritancePersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Doctrine\ORM\Persisters\Entity;

use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Mapping\ClassMetadata;

use function sprintf;
Expand Down Expand Up @@ -57,7 +56,7 @@ protected function getSelectColumnSQL(string $field, ClassMetadata $class, strin

$this->currentPersisterContext->rsm->addFieldResult($alias, $columnAlias, $field, $class->name);

$type = Type::getType($fieldMapping->type);
$type = $this->getType($fieldMapping->type);
$sql = $type->convertToPHPValueSQL($sql, $this->platform);

return $sql . ' AS ' . $columnAlias;
Expand Down
15 changes: 10 additions & 5 deletions src/Persisters/Entity/BasicEntityPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,11 @@ final protected function updateFilterHash(): void
$this->filterHash = $this->em->getFilters()->getHash();
}

final protected function getType(string $name): Type
{
return $this->em->getConfiguration()->getTypeRegistry()->get($name);
}

public function getClassMetadata(): ClassMetadata
{
return $this->class;
Expand Down Expand Up @@ -292,7 +297,7 @@ protected function assignDefaultVersionAndUpsertableValues(object $entity, array
$values = $this->fetchVersionAndNotUpsertableValues($this->class, $id);

foreach ($values as $field => $value) {
$value = Type::getType($this->class->fieldMappings[$field]->type)->convertToPHPValue($value, $this->platform);
$value = $this->getType($this->class->fieldMappings[$field]->type)->convertToPHPValue($value, $this->platform);

$this->class->setFieldValue($entity, $field, $value);
}
Expand Down Expand Up @@ -418,7 +423,7 @@ final protected function updateTable(
$column = $this->quoteStrategy->getColumnName($fieldName, $this->class, $this->platform);

if (isset($this->class->fieldMappings[$fieldName])) {
$type = Type::getType($this->columnTypes[$columnName]);
$type = $this->getType($this->columnTypes[$columnName]);
$placeholder = $type->convertToDatabaseValueSQL('?', $this->platform);
}

Expand Down Expand Up @@ -1457,7 +1462,7 @@ public function getInsertSQL(): string
&& isset($this->columnTypes[$this->class->fieldNames[$column]])
&& isset($this->class->fieldMappings[$this->class->fieldNames[$column]])
) {
$type = Type::getType($this->columnTypes[$this->class->fieldNames[$column]]);
$type = $this->getType($this->columnTypes[$this->class->fieldNames[$column]]);
$placeholder = $type->convertToDatabaseValueSQL('?', $this->platform);
}

Expand Down Expand Up @@ -1543,7 +1548,7 @@ protected function getSelectColumnSQL(string $field, ClassMetadata $class, strin
$this->currentPersisterContext->rsm->addEnumResult($columnAlias, $fieldMapping->enumType);
}

$type = Type::getType($fieldMapping->type);
$type = $this->getType($fieldMapping->type);
$sql = $type->convertToPHPValueSQL($sql, $this->platform);

return $sql . ' AS ' . $columnAlias;
Expand Down Expand Up @@ -1650,7 +1655,7 @@ public function getSelectConditionStatementSQL(
$placeholder = '?';

if (isset($this->class->fieldMappings[$field])) {
$type = Type::getType($this->class->fieldMappings[$field]->type);
$type = $this->getType($this->class->fieldMappings[$field]->type);
$placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->platform);
}

Expand Down
3 changes: 1 addition & 2 deletions src/Persisters/Entity/JoinedSubclassPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Doctrine\Common\Collections\Criteria;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Internal\SQLResultCasing;
use Doctrine\ORM\Mapping\AssociationMapping;
Expand Down Expand Up @@ -511,7 +510,7 @@ protected function assignDefaultVersionAndUpsertableValues(object $entity, array
$values = $this->fetchVersionAndNotUpsertableValues($this->getVersionedClassMetadata(), $id);

foreach ($values as $field => $value) {
$value = Type::getType($this->class->fieldMappings[$field]->type)->convertToPHPValue($value, $this->platform);
$value = $this->getType($this->class->fieldMappings[$field]->type)->convertToPHPValue($value, $this->platform);

$this->class->setFieldValue($entity, $field, $value);
}
Expand Down
3 changes: 1 addition & 2 deletions src/Query/Exec/MultiTableDeleteExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Query\AST;
use Doctrine\ORM\Query\AST\DeleteStatement;
use Doctrine\ORM\Query\SqlWalker;
Expand Down Expand Up @@ -90,7 +89,7 @@ public function __construct(AST\Node $AST, SqlWalker $sqlWalker)
$columnDefinitions[$idColumnName] = [
'name' => $idColumnName,
'notnull' => true,
'type' => Type::getType(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $em)),
'type' => $em->getConfiguration()->getTypeRegistry()->get(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $em)),
];
}

Expand Down
3 changes: 1 addition & 2 deletions src/Query/Exec/MultiTableUpdateExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Query\AST;
use Doctrine\ORM\Query\AST\UpdateStatement;
use Doctrine\ORM\Query\ParameterTypeInferer;
Expand Down Expand Up @@ -130,7 +129,7 @@ public function __construct(AST\Node $AST, SqlWalker $sqlWalker)
$columnDefinitions[$idColumnName] = [
'name' => $idColumnName,
'notnull' => true,
'type' => Type::getType(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $em)),
'type' => $em->getConfiguration()->getTypeRegistry()->get(PersisterHelper::getTypeOfColumn($idColumnName, $rootClass, $em)),
];
}

Expand Down
3 changes: 1 addition & 2 deletions src/Query/ResultSetMappingBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Doctrine\ORM\Query;

use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Internal\SQLResultCasing;
use Doctrine\ORM\Mapping\ClassMetadata;
Expand Down Expand Up @@ -253,7 +252,7 @@ public function generateSelectClause(array $tableAliases = []): string
$classFieldMapping = $class->fieldMappings[$fieldName];
$columnSql = $tableAlias . '.' . $classFieldMapping->columnName;

$type = Type::getType($classFieldMapping->type);
$type = $this->em->getConfiguration()->getTypeRegistry()->get($classFieldMapping->type);
$columnSql = $type->convertToPHPValueSQL($columnSql, $this->em->getConnection()->getDatabasePlatform());

$sql .= $columnSql;
Expand Down
19 changes: 11 additions & 8 deletions src/Query/SqlWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\TypeRegistry;
use Doctrine\DBAL\Types\Types;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\EntityManagerInterface;
Expand Down Expand Up @@ -142,6 +142,8 @@ class SqlWalker
*/
private readonly QuoteStrategy $quoteStrategy;

private readonly TypeRegistry $typeRegistry;

/** @phpstan-param array<string, QueryComponent> $queryComponents The query components (symbol table). */
public function __construct(
private readonly Query $query,
Expand All @@ -153,6 +155,7 @@ public function __construct(
$this->conn = $this->em->getConnection();
$this->platform = $this->conn->getDatabasePlatform();
$this->quoteStrategy = $this->em->getConfiguration()->getQuoteStrategy();
$this->typeRegistry = $this->em->getConfiguration()->getTypeRegistry();
}

/**
Expand Down Expand Up @@ -1298,7 +1301,7 @@ public function walkSelectExpression(AST\SelectExpression $selectExpression): st
$columnAlias = $this->getSQLColumnAlias($fieldMapping->columnName);
$col = $sqlTableAlias . '.' . $columnName;

$type = Type::getType($fieldMapping->type);
$type = $this->typeRegistry->get($fieldMapping->type);
$col = $type->convertToPHPValueSQL($col, $this->conn->getDatabasePlatform());

$sql .= $col . ' AS ' . $columnAlias;
Expand Down Expand Up @@ -1354,7 +1357,7 @@ public function walkSelectExpression(AST\SelectExpression $selectExpression): st
);

// @phpstan-ignore method.deprecatedInterface
$this->rsm->addScalarResult($columnAlias, $resultAlias, Type::getTypeRegistry()->lookupName($expr->getReturnType()));
$this->rsm->addScalarResult($columnAlias, $resultAlias, $this->typeRegistry->lookupName($expr->getReturnType()));

break;
}
Expand Down Expand Up @@ -1439,7 +1442,7 @@ public function walkObjectExpression(string $dqlAlias, array $partialFieldSet, s

$col = $sqlTableAlias . '.' . $quotedColumnName;

$type = Type::getType($mapping->type);
$type = $this->typeRegistry->get($mapping->type);
$col = $type->convertToPHPValueSQL($col, $this->platform);

$sqlParts[] = $col . ' AS ' . $columnAlias;
Expand Down Expand Up @@ -1474,7 +1477,7 @@ public function walkObjectExpression(string $dqlAlias, array $partialFieldSet, s

$col = $sqlTableAlias . '.' . $quotedColumnName;

$type = Type::getType($mapping->type);
$type = $this->typeRegistry->get($mapping->type);
$col = $type->convertToPHPValueSQL($col, $this->platform);

$sqlParts[] = $col . ' AS ' . $columnAlias;
Expand Down Expand Up @@ -1579,7 +1582,7 @@ public function walkNewObject(AST\NewObjectExpression $newObjectExpression, stri
$fieldType = $fieldMapping->type;
$col = trim($e->dispatch($this));

$type = Type::getType($fieldType);
$type = $this->typeRegistry->get($fieldType);
$col = $type->convertToPHPValueSQL($col, $this->platform);

$sqlSelectExpressions[] = $col . ' AS ' . $columnAlias;
Expand Down Expand Up @@ -2213,8 +2216,8 @@ public function walkInputParameter(AST\InputParameter $inputParam): string

if ($parameter) {
$type = $parameter->getType();
if (is_string($type) && Type::hasType($type)) {
return Type::getType($type)->convertToDatabaseValueSQL('?', $this->platform);
if (is_string($type) && $this->typeRegistry->has($type)) {
return $this->typeRegistry->get($type)->convertToDatabaseValueSQL('?', $this->platform);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/Tools/Pagination/LimitSubqueryWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Doctrine\ORM\Tools\Pagination;

use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\AST\Functions\IdentityFunction;
use Doctrine\ORM\Query\AST\Node;
Expand Down Expand Up @@ -51,7 +50,7 @@ public function walkSelectStatement(SelectStatement $selectStatement): void

$query->setHint(
self::IDENTIFIER_TYPE,
Type::getType($rootClass->fieldMappings[$identifier]->type),
$query->getEntityManager()->getConfiguration()->getTypeRegistry()->get($rootClass->fieldMappings[$identifier]->type),
);

$query->setHint(self::FORCE_DBAL_TYPE_CONVERSION, true);
Expand Down
6 changes: 3 additions & 3 deletions src/Tools/SchemaValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public function validateClass(ClassMetadata $class): array
$cmf = $this->em->getMetadataFactory();

foreach ($class->fieldMappings as $fieldName => $mapping) {
if (! Type::hasType($mapping->type)) {
if (! $this->em->getConfiguration()->getTypeRegistry()->has($mapping->type)) {
$ce[] = "The field '" . $class->name . '#' . $fieldName . "' uses a non-existent type '" . $mapping->type . "'.";
}
}
Expand Down Expand Up @@ -343,7 +343,7 @@ function (FieldMapping $fieldMapping) use ($class): string|null {
$propertyType = $class->propertyAccessors[$fieldName]->getUnderlyingReflector()->getType();

// If the field type is not a built-in type, we cannot check it
if (! Type::hasType($fieldMapping->type)) {
if (! $this->em->getConfiguration()->getTypeRegistry()->has($fieldMapping->type)) {
return null;
}

Expand All @@ -352,7 +352,7 @@ function (FieldMapping $fieldMapping) use ($class): string|null {
return null;
}

$metadataFieldType = $this->findBuiltInType(Type::getType($fieldMapping->type));
$metadataFieldType = $this->findBuiltInType($this->em->getConfiguration()->getTypeRegistry()->get($fieldMapping->type));

//If the metadata field type is not a mapped built-in type, we cannot check it
if ($metadataFieldType === null) {
Expand Down
Loading
Loading