atk4 / data

Data Access PHP Framework for SQL & high-latency databases
https://atk4-data.readthedocs.io
MIT License
271 stars 46 forks source link

Model::dirty not available in Model::HOOK_AFTER_SAVE spot #1130

Closed PhilippGrashoff closed 1 year ago

PhilippGrashoff commented 1 year ago

The current decription of Model::dirty indicates that the dirty information is available in all hooks: * The $dirty data will be reset after you save() the data but it is still available to all before/after save handlers.

However, that is not the case. Model::dirty is reset before the Model::HOOK_AFTER_SAVE spot is executed (taken from current develop):

            $dirtyRef = &$this->getDirtyRef();
            $dirtyRef = [];

            if ($this->idField && $this->reloadAfterSave) {
                $this->reload();
            }

            $this->hook(self::HOOK_AFTER_SAVE, [$isUpdate]);

It is not enough to move the reset after the hook, as Model::reload() also resets dirty. This is where is gets complicated: reloaded model information could be important in the after save hook, as does the dirty information does.

The only fix I can think of is to clone $dirtyRef, assign in to $this right before the hook is executed and then reset it afterwards. Something like:

            $dirtyRef = &$this->getDirtyRef();
            $dirtyRefCache = clone dirtyRef;

            if ($this->idField && $this->reloadAfterSave) {
                $this->reload();
            }

            $dirtyRef = $dirtyRefCache;
            $this->hook(self::HOOK_AFTER_SAVE, [$isUpdate]);
            $dirtyRef = [];

WDYT about this? If you are fine with this, I will create a PR with a change like this and add a test.

mvorisek commented 1 year ago

You can capture the original dirty data in "before update" hook. The dirtiness is logical, before update, the data are dirty as they are. Once they are saved, they are no longer dirty.