Replace static Type::* calls with instance-based TypeRegistry lookups - #12421
Replace static Type::* calls with instance-based TypeRegistry lookups#12421GromNaN wants to merge 5 commits into
Type::* calls with instance-based TypeRegistry lookups#12421Conversation
Type::* calls with instance-based TypeRegistry lookupsType::* calls with instance-based TypeRegistry lookups
This indicates a flaw in the architecture IMO. If |
|
There hasn't been any activity on this pull request in the past 90 days, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 7 days. |
|
Thanks @stof, you're right. The two static fallbacks in I'd like to expose the type name (string) instead. Two options:
|
460fdc9 to
0bc9c35
Compare
All internal callers now resolve types through Configuration::getTypeRegistry() rather than the global static Type::getType() / Type::hasType() / Type::getTypeRegistry() methods. Remaining static calls are justified fallbacks: - Configuration::getTypeRegistry() falls back to Type::getTypeRegistry() for DBAL v3 compatibility (no Configuration::getTypeRegistry() there) - LengthFunction and CountFunction: getReturnType() has no EM access, accessing built-in INTEGER type only - DatabaseDriver: deprecated class, no EM access available
… methods Replace getType()/hasType() helpers with a $typeRegistry property initialized in the constructor, avoiding repeated getConfiguration()->getTypeRegistry() chain calls.
0bc9c35 to
24a4f03
Compare
|
Rebased on top of #12543 (now merged into 3.7.x). The concern raised by @stof about |
| use Doctrine\DBAL\ArrayParameterType; | ||
| use Doctrine\DBAL\ParameterType; | ||
| use Doctrine\DBAL\Types\Type; | ||
| use Doctrine\DBAL\Types\Types; |
There was a problem hiding this comment.
this use statement must not be removed. It is still used to access constants (see the SA errors)
| { | ||
| // @phpstan-ignore function.alreadyNarrowedType (method_exists check is for DBAL v3 compatibility) | ||
| if (method_exists(parent::class, 'getTypeRegistry')) { | ||
| return parent::getTypeRegistry(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
351b8de to
2f40411
Compare
GromNaN
left a comment
There was a problem hiding this comment.
Waiting for doctrine/dbal#7342
|
Btw, I think it would make sense to first work on fixing CI failures in the 3.7.x branch instead of merging PRs without a working CI. |
Kind of weird we seem not to have a rule enforcing that. I'll look into it, this looks highly irregular. EDIT: in fact, this is probably normal, it's just that I'm not used to seeing PRs with failing checks that are also approved, I think. |
…ration The type registry belongs to the DBAL Configuration used to create the connection, not to the ORM Configuration. Both are configured independently in DoctrineBundle, so they are not guaranteed to share the same registry. Introduce Internal\TypeRegistryLocator::fromConnection() to resolve the registry from the connection, with a fallback to the global registry on DBAL < 4.5. Restore the Types import in PersisterHelper (still used for constants).
TypeRegistryLocator::fromConnection() was called inside loops (temporary table column definitions, schema validation, select clause generation) and once per parameter in array_map. Hoist the lookup to a local variable before the loop, or to a readonly property populated in the constructor for the per-field helpers in AbstractHydrator and BasicEntityPersister. getArrayBindingType() now receives the TypeRegistry instead of the EntityManager, so it is resolved a single time per inferParameterTypes() call.
2f40411 to
38c65bf
Compare
DBAL 4.5 exposes Configuration::getTypeProvider() returning the new Doctrine\DBAL\Types\TypeProvider interface rather than the final TypeRegistry, so the type source is no longer required to be that concrete class. Renamed TypeRegistryLocator to TypeProviderLocator accordingly, along with the $typeRegistry properties and locals it feeds. The declared types are unions of TypeProvider and TypeRegistry, because the interface only exists as of DBAL 4.5 while these code paths still support older versions. PHP matches the first applicable member of a union and never loads the other, so the union resolves fine when TypeProvider is absent, whereas a sole TypeProvider type would raise a TypeError. Every such union sits on a private property, a private parameter, or the @internal locator, so none of it reaches the public API. DatabaseDriver now reads Column::getTypeName() instead of looking a name back up from an instance, which drops two deprecated calls at once. SqlWalker's deprecated TypedExpression branch keeps using Type::lookupName(), since a Type instance is all it has; both are deprecated and will be removed together.
c1273c9 to
f4dd7a1
Compare
Related to doctrine/dbal#7342
All internal callers now resolve types through
Configuration::getTypeRegistry()rather than the global staticType::getType()/Type::hasType()/Type::getTypeRegistry()methods. InSqlWalker, the registry is fetched once in the constructor and stored in a$typeRegistryproperty, avoiding repeatedgetConfiguration()->getTypeRegistry()chains.Remaining static calls are justified fallbacks:
Configuration::getTypeRegistry()falls back toType::getTypeRegistry()for DBAL v3 and 4.0 compatibility (noConfiguration::getTypeRegistry()there)DatabaseDriver: deprecated class, no EM access available