-
-
Notifications
You must be signed in to change notification settings - Fork 39
Bug new values incorrect detection #526
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: master
Are you sure you want to change the base?
Bug new values incorrect detection #526
Conversation
… that DATE gets converted to DateTimeImmutable and matches the DB value.
…s correctly including localized time zone. Fix false positives when comparing DateTimeInterface objects.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #526 +/- ##
=============================================
- Coverage 100.00% 99.93% -0.07%
- Complexity 654 657 +3
=============================================
Files 43 43
Lines 1632 1612 -20
=============================================
- Hits 1632 1611 -21
- Misses 0 1 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
I managed to get running the tests with different DB drivers - it turns out I missed your makefile in this repo making running the tests with corresponding docker services a breeze :) Unfortunately, I have to adjust the tests based on the DB drivers, because DATETIME columns are different depending on the DBMS and not always supports storing the timezone. Give me some time to adjust the tests. |
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 fixes a bug in AbstractActiveRecord::newValues() where DateTimeInterface attributes were incorrectly marked as changed due to strict object comparison (!==). The fix compares DateTimeInterface objects by their formatted string representation (Y-m-d\TH:i:s.uP), which includes timezone information, preventing false positives while still detecting genuine changes including timezone differences.
Key changes:
- Modified
newValues()method to use formatted string comparison forDateTimeInterfaceobjects - Added comprehensive test coverage for DateTime comparison scenarios
- Updated test fixtures with
registered_atcolumn and data to support DateTime testing
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/AbstractActiveRecord.php | Core fix: Added special handling for DateTimeInterface comparison using formatted strings instead of strict object comparison |
| tests/ActiveRecordTest.php | Added test provider and test method covering new records, unchanged DateTime values, and timezone-different DateTime values |
| tests/ActiveQueryTest.php | Added tests verifying newValues() behavior with same/different moments in time; updated existing test expectations |
| tests/ActiveQueryFindTest.php | Updated test expectations to include the new registered_at field |
| tests/ArrayableTraitTest.php | Updated test expectations to include the new registered_at field in toArray() output |
| tests/Stubs/ActiveRecord/Customer.php | Added registered_at property and getter/setter; implemented fields() method to format DateTime for array serialization |
| tests/Stubs/ActiveRecord/CustomerClosureField.php | Added registered_at property and field formatter in fields() method |
| tests/data/sqlite.sql | Added registered_at column to customer table and populated test data with DateTime values including timezone information |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $result[$name] = $value; | ||
| foreach (array_diff_key($currentValues, $newValues) as $name => $newValue) { | ||
| if ($newValue instanceof DateTimeInterface) { | ||
| if ($oldValues[$name] === null |
Copilot
AI
Jan 1, 2026
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.
When the new value is a DateTimeInterface, the code checks if the old value is null but doesn't verify that the old value also implements DateTimeInterface before calling format() on it at line 130. If the old value is a non-null value that doesn't implement DateTimeInterface (e.g., a string), this will cause a fatal error. Consider adding an additional check: || !($oldValues[$name] instanceof DateTimeInterface) to the condition at line 129.
| if ($oldValues[$name] === null | |
| if ($oldValues[$name] === null | |
| || !($oldValues[$name] instanceof DateTimeInterface) |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Problem
AbstractActiveRecord::newValues()uses strict comparison (!==) also forDateTimeInterfaceattributes,which causes identical date/time values to be marked as changed because they are different objects.
Solution
If the new value implement
DateTimeInterface, compare both objects by comparing the formatted dateY-m-d\TH:i:s.uP, e.g.: 2011-02-03T04:05:06.123456+01:00.This fixes false positives and works also when two different date time objects represents the same moment in time but have different time zones.
E.g.:
... they both represent the same moment in time, but the formatted string is clearly different and thus can be detected as changed by the
newValues()function.Tests
Added tests to cover: