Skip to content
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

Fix change detection for non-scalar readonly properties #9998

Closed
wants to merge 2 commits into from

Conversation

nCrazed
Copy link

@nCrazed nCrazed commented Aug 17, 2022

No description provided.

This fixes a bug where non-scalar readonly properties (like Uuid) will
cause an "Attempting to change readonly property..." error despite the
underlying value not actually changing.

The implementation isn't for a specific object type like the ones provided by
symfony/uid (which is used in the new test cases), but instead relies on the
common convention of value objects defining an equals() method for correct
equality checking.
@beberlei
Copy link
Member

This has no relation with readonly properties. Other types doont allow object compare via equals() either.

@@ -47,6 +47,7 @@
"psr/log": "^1 || ^2 || ^3",
"squizlabs/php_codesniffer": "3.7.1",
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
"symfony/uid": "^4.4 || ^5.4 || ^6.0",
Copy link
Member

Choose a reason for hiding this comment

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

I'm not keen on adding that dependency, tbh. We should be able to reproduce the problem without it.

Copy link
Author

Choose a reason for hiding this comment

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

That's fair. I only added it because it's technically supposed to be supported out of the box (but that might be a symfony concern, so it makes sense to not add it in doctrine)

{
$objectValue = parent::getValue($object);

if (is_object($objectValue) && method_exists($objectValue, 'equals')) {
Copy link
Member

Choose a reason for hiding this comment

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

I'm not comfortable with applying duck typing here. I understand the problem that you're trying to solve, but I'd rather not compare incomparable values than to guess how to compare them.

Copy link
Author

Choose a reason for hiding this comment

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

I am not fan of duck typing here either, but other than adding explicit type checks (and thus requiring a non-dev dependency for every supported type), I am not sure how else the problem could be fixed

Copy link
Member

Choose a reason for hiding this comment

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

I mean, we could just assume equality if we cannot compare the values. I would prefer that solution over calling a method that just looks like it does the right thing…

Copy link
Author

Choose a reason for hiding this comment

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

Would exposing a configuration hook for providing custom equality checks be acceptable here?

Copy link
Author

Choose a reason for hiding this comment

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

The above question still stands. I am happy to work towards another fix, but would like a confirmation that the approach is acceptable before I do so

@derrabus derrabus added the Bug label Aug 17, 2022
@nCrazed
Copy link
Author

nCrazed commented Aug 17, 2022

@beberlei the failure I am attempting to fix is specific to readonly property support. The one of the added test cases (same) fails without the change and the error that comes out of it is blatantly incorrect

@nCrazed
Copy link
Author

nCrazed commented Aug 18, 2022

Not sure how I missed this related issue: #9505

@icanhazstring
Copy link

icanhazstring commented Mar 27, 2024

This has been stale for quite some time now.
As mentioned by @nCrazed, one solution could be a configurable map or general method that should be supported.

doctrine:
    orm:
        type_comparison:
            # Map of methods that check for equality
            default: 'equals' # default for every other object type or even just fallback to that !== comarison
            Symfony\Uid\Uuid: 'compare'

This way, the UnitOfWork can also use this to compute changes. There are no changes when I generate a Uuid with the same string twice except having another object hash.

If that sounds like a good plan, please let us know. So we can get this feature integrated into doctrine.

@derrabus
Copy link
Member

I think, we can close this PR because of implementation issues. I'll happily review a new attempt that works without additional dependencies or duck typing. Some kind of discovery mechanism for comparator functions as suggested could be the solution, but I'm not sure about that.

@derrabus derrabus closed this Apr 17, 2024
@nCrazed
Copy link
Author

nCrazed commented Apr 17, 2024

An alternative was suggested, but never approved/declined 🤷‍♂️

@icanhazstring
Copy link

icanhazstring commented Apr 18, 2024

Closing it is good and all. But we gave some suggestions and got no feedback for it.

The current behavior is clearly a bug and should be fixed. I think @nCrazed and I both would be happy to contribute, but we would kindly appreciate any kind of feedback to the proposed suggestion(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants