-
-
Notifications
You must be signed in to change notification settings - Fork 513
Improve detection of the type from a PHP variable #2814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 2.13.x
Are you sure you want to change the base?
Conversation
|
||
.. code-block:: php | ||
|
||
#[Field(type: Uuid::class)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting the custom type here should not be necessary. As soon as you register a type with the value object type name, it should be registered automatically
mongodb-odm/lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadata.php
Lines 2771 to 2793 in afb565e
switch ($type->getName()) { | |
case DateTime::class: | |
$mapping['type'] = Type::DATE; | |
break; | |
case DateTimeImmutable::class: | |
$mapping['type'] = Type::DATE_IMMUTABLE; | |
break; | |
case 'array': | |
$mapping['type'] = Type::HASH; | |
break; | |
case 'bool': | |
$mapping['type'] = Type::BOOL; | |
break; | |
case 'float': | |
$mapping['type'] = Type::FLOAT; | |
break; | |
case 'int': | |
$mapping['type'] = Type::INT; | |
break; | |
case 'string': | |
$mapping['type'] = Type::STRING; | |
break; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it clear from this example that you're referencing Ramsey\Uuid\Uuid
? There's no use
statement and this is a separate code block from the custom type class above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to use the FQCN.
Type::addType(Ramsey\Uuid\Uuid::class, My\Project\Types\UuidType::class); | ||
|
||
.. note:: | ||
The type name should match the support class name (e.g., ``uuid`` for ``UuidType``) to enable automatic association with the field type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the automatic association, how does that work? Does it take everything before the Type
suffix? How does it handle casing, e.g. in FooBarType
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not certain, but I think this might utilize doctrine/inflector internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be helpful to add here what format would constitute a match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, there is no such magic. The name should be the class name of the value object.
|
||
You can create a custom mapping type for your own value objects or classes. For | ||
example, to map a UUID value object using the `ramsey/uuid library`_, you can | ||
implement a type that converts between your class and the MongoDB binary format. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this say "BSON binary format", or do you think that'd just be more confusing for users? OK to leave as-is.
sprintf( | ||
'Could not convert database value "%s" from "%s" to %s', | ||
$value, | ||
get_debug_type($value), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are use function
lines necessary? I'm OK to omit them, but just want to ensure you've considered the question.
|
||
.. code-block:: php | ||
|
||
#[Field(type: Uuid::class)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it clear from this example that you're referencing Ramsey\Uuid\Uuid
? There's no use
statement and this is a separate code block from the custom type class above.
Type::addType(Ramsey\Uuid\Uuid::class, My\Project\Types\UuidType::class); | ||
|
||
.. note:: | ||
The type name should match the support class name (e.g., ``uuid`` for ``UuidType``) to enable automatic association with the field type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not certain, but I think this might utilize doctrine/inflector internally.
|
||
This pattern can be adapted for any custom class—just implement the conversion logic for your value object. | ||
|
||
.. |FQCN| raw:: html <abbr title="Fully-Qualified Class Name">FQCN</abbr> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@GromNaN: this looks like it may be a false positive, since this is some very niche RST syntax
.. note:: | ||
The type name should match the support class name (e.g., ``uuid`` for ``UuidType``) to enable automatic association with the field type. | ||
|
||
This pattern can be adapted for any custom class—just implement the conversion logic for your value object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same feedback here as @paulinevos' thread above re: "class-just"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence was duplicate if the previous one. I removed it.
{ | ||
public static function invalidTypeName(string $name): self | ||
{ | ||
return new self(sprintf('Invalid type specified "%s".', $name)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this use a colon?
return new self(sprintf('Invalid type specified "%s".', $name)); | |
return new self(sprintf('Invalid type specified: "%s".', $name)); |
'integer' => self::getType('int'), | ||
'boolean' => self::getType('bool'), | ||
'double' => self::getType('float'), | ||
'string' => self::getType('string'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason you're not referencing the constants here, as you did above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No reason. Updated.
relying on an exception is inefficient
… is the FQCN of the value object
d446495
to
d106a5a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review. I added the type detection for DTO class name in property type.
Type::addType(Ramsey\Uuid\Uuid::class, My\Project\Types\UuidType::class); | ||
|
||
.. note:: | ||
The type name should match the support class name (e.g., ``uuid`` for ``UuidType``) to enable automatic association with the field type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, there is no such magic. The name should be the class name of the value object.
.. note:: | ||
The type name should match the support class name (e.g., ``uuid`` for ``UuidType``) to enable automatic association with the field type. | ||
|
||
This pattern can be adapted for any custom class—just implement the conversion logic for your value object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence was duplicate if the previous one. I removed it.
|
||
This pattern can be adapted for any custom class—just implement the conversion logic for your value object. | ||
|
||
.. |FQCN| raw:: html <abbr title="Fully-Qualified Class Name">FQCN</abbr> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I revert changes on this line. I'm not sure how this will be formatted.
|
||
.. code-block:: php | ||
|
||
#[Field(type: Uuid::class)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to use the FQCN.
'integer' => self::getType('int'), | ||
'boolean' => self::getType('bool'), | ||
'double' => self::getType('float'), | ||
'string' => self::getType('string'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No reason. Updated.
By using the |FQCN| of the value object class as the type name, the type is | ||
automatically used when encountering a property of that class. This means you | ||
can omit the ``type`` option when defining the field mapping:: | ||
|
||
.. code-block:: php | ||
|
||
#[Field] | ||
public Ramsey\Uuid\Uuid $id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a new feature that can compete with embedded documents: adding custom logic to convert a value object into BSON.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have a global namespace for exception like it is generally done in libraries. Existing exception names are:
Doctrine\ODM\MongoDB\MongoDBException
Doctrine\ODM\MongoDB\ConfigurationException
Doctrine\ODM\MongoDB\DocumentNotFoundException
Doctrine\ODM\MongoDB\Mapping\MappingException
Doctrine\ODM\MongoDB\Hydrator\HydratorException
Doctrine\ODM\MongoDB\LockException
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR improves type detection for PHP variables in the MongoDB ODM by enhancing the getTypeFromPHPVariable
method to automatically detect custom types based on object class names. The change allows custom types registered using their FQCN to be automatically selected when processing aggregation expressions.
Key changes:
- Enhanced type detection to check if an object's class name corresponds to a registered custom type
- Improved exception handling by introducing a dedicated
InvalidTypeException
- Added automatic type inference for object properties when custom types are registered with class FQCNs
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
File | Description |
---|---|
lib/Doctrine/ODM/MongoDB/Types/Type.php |
Enhanced getTypeFromPHPVariable method to detect custom types by class name and improved type detection logic |
lib/Doctrine/ODM/MongoDB/Types/InvalidTypeException.php |
New dedicated exception class for invalid type scenarios |
lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadata.php |
Added automatic type detection for properties with registered custom types |
tests/Doctrine/ODM/MongoDB/Tests/Types/TypeTest.php |
Added comprehensive test coverage for the new type detection functionality |
tests/Doctrine/ODM/MongoDB/Tests/Functional/CustomTypeTest.php |
Added tests demonstrating custom type detection and proper test setup/teardown |
tests/Doctrine/ODM/MongoDB/Tests/Functional/Ticket/GH2789Test.php |
Improved test isolation by properly managing type registry state |
docs/en/reference/custom-mapping-types.rst |
Updated documentation with UUID custom type example and FQCN usage patterns |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
Summary
The method
getTypeFromPHPVariable
is used only byconvertPHPToDatabaseValue
. Which is used to process expressions in the aggregation builder.With this new feature, we try to find the type for object class name; assuming custom types are registered using the FQCN of the objects they store.