-
-
Notifications
You must be signed in to change notification settings - Fork 514
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
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.
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.
The use function
are not necessary for global functions. That's a CS preference to use them. I omit them for brevity in the example.
|
||
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
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.
|
||
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.
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.
Maybe the example should be with a custom class instead, since UUID are new supported using symfony/uid
#2826
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.
return $value; | ||
} | ||
if ($value instanceof Binary) { |
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.
Would it make sense to restrict this to a MongoDB\BSON\Binary where getType()
returns either TYPE_OLD_UUID
or TYPE_UUID
? As-is, it's not clear what would happen if you encountered binary data from the server with a different sub-type.
I'll note that convertToDatabaseValue()
yields a Binary object with TYPE_UUID
, so perhaps there's no reason to accept TYPE_OLD_UUID
here.
If you are intentionally being liberal in what you accept and conservative in what you emit (Robustness Principle) and would like to leave this as-is, that's fine by me. You can optionally add a comment here explaining that design decision for the benefit of readers.
return null; | ||
} | ||
if ($value instanceof Binary) { |
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.
Would you want to ensure you always yield a Binary with sub-type TYPE_UUID
? If so, you might need to split this into two separate conditionals.
if ($value instanceof Binary && $value->getType() !== Binary::TYPE_UUID) {
// Note: this may throw if the data is not exactly 16 bytes
return new Binary($value->getBytes(), Binary::TYPE_UUID);
}
if ($value instanceof Binary) {
return $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.
I'd rather simplify the example.
https://github.com/doctrine/mongodb-odm/pull/2814/files#r2393846289
<field field-name="field" type="date_with_timezone" /> | ||
Custom Type Example: Mapping a 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.
Note: I'm currently working on adding a type for Symfony UUIDs as I needed them for a project. That would make this entire chapter obsolete.
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.
The chapter is about mapping a DTO with a custom type. UUID is only an example, we can find an other example.
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.
The use function
are not necessary for global functions. That's a CS preference to use them. I omit them for brevity in the example.
if (null === $value || [] === $value) { | ||
return null; | ||
} | ||
if ($value instanceof Binary) { | ||
return $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.
I can simplify the example and remove this edge cases.
if (null === $value || [] === $value) { | |
return null; | |
} | |
if ($value instanceof Binary) { | |
return $value; | |
} | |
if (null === $value) { | |
return null; | |
} |
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.
Without the $value instanceof Binary
check, wouldn't the method then throw InvalidArgumentException for a Binary value? Or are you comfortable assuming that a Binary would never be passed in?
I didn't follow why []
was originally being handled alongside null
, so I don't have much thought on that change.
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 the example of document class, the property has the ?\Ramsey\Uuid\Uuid
type, which ensure the RamseyUuidType::convertToDatabaseValue()
method never get anything else.
As soon as the field value is the database is not corrupted, the simple implementation will work perfectly. No need to add support for edge cases that are never encountered.
return null; | ||
} | ||
if ($value instanceof Binary) { |
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'd rather simplify the example.
https://github.com/doctrine/mongodb-odm/pull/2814/files#r2393846289
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.
Maybe the example should be with a custom class instead, since UUID are new supported using symfony/uid
#2826
30cb393
to
d1ea68b
Compare
d1ea68b
to
840f7b8
Compare
840f7b8
to
f0ecc10
Compare
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.