Description
When an entity is created with new, inserted via save(), and then mutated and passed to save() again in the same request, the UPDATE is silently skipped and no exception is thrown.
Root cause:
Repository::update() calls EntityHydrator::getDirtyProperties() to determine which columns changed. That method compares current values against an $originalValues map that is only populated by
EntityHydrator::hydrate() — i.e. when an entity is read from the database.
When save() performs an INSERT, it sets the primary key via reflection but never registers the entity's state in $originalValues. The map stays empty, getDirtyProperties() returns [], and update() returns early without executing any SQL.
Suggested fix:
After the INSERT query completes, call a hydrator method (e.g. registerOriginalValues($entity, $metadata)) that snapshots the entity's current property values into $originalValues — mirroring what hydrate() does when loading from the database.
Workaround:
Re-fetch the entity from the database after inserting before applying further changes:
$repository->save($entity);
$entity = $repository->find($entity->id); // hydrates $originalValues correctly
$entity->status = 'completed';
$repository->save($entity); // UPDATE works as expected
Steps to Reproduce
$entity = new Transaction();
$entity->status = 'pending';
// ... set required fields
$repository->save($entity); // INSERT — $entity->id is now set
$entity->status = 'completed';
$repository->save($entity); // Expected: UPDATE — Actual: no-op
Expected Behavior
After a successful INSERT, the entity's current state should be registered as its original values so that subsequent save() calls correctly detect and persist changes.
Actual Behavior
The new values aren't persisted to the database.
Package
database
PHP Version
8.5
Marko Version
0.3.0
Description
When an entity is created with new, inserted via save(), and then mutated and passed to save() again in the same request, the UPDATE is silently skipped and no exception is thrown.
Root cause:
Repository::update()callsEntityHydrator::getDirtyProperties()to determine which columns changed. That method compares current values against an $originalValues map that is only populated byEntityHydrator::hydrate()— i.e. when an entity is read from the database.When
save()performs an INSERT, it sets the primary key via reflection but never registers the entity's state in$originalValues. The map stays empty,getDirtyProperties()returns[], andupdate()returns early without executing any SQL.Suggested fix:
After the INSERT query completes, call a hydrator method (e.g.
registerOriginalValues($entity, $metadata))that snapshots the entity's current property values into $originalValues — mirroring whathydrate()does when loading from the database.Workaround:
Re-fetch the entity from the database after inserting before applying further changes:
Steps to Reproduce
Expected Behavior
After a successful INSERT, the entity's current state should be registered as its original values so that subsequent
save()calls correctly detect and persist changes.Actual Behavior
The new values aren't persisted to the database.
Package
database
PHP Version
8.5
Marko Version
0.3.0