Using Agile Data to keep spouses together

#1

I thought that topic might get some interest, but it’s a genuine issue I’m facing. I have an application that knows about spouses and, of course, if person a’s spouse is b, then person b’s spouse is a. So I thought of using a beforeUpdate hook to, if the spouse id changed, update the old spouse’s spouse ID to null and update the new spouse’s ID to the ID of the current record.

But wait a minute…if I do that, then when I’m updating the the old spouse’s record I will end up calling the beforeUpdate routine for that record… which will update the old spouse’s spouse’s record, which will end up calling the beforeUpdate routine…and on and on until the server runs out of memory.

My workaround was to create a new database field ‘updatingSpouse’ and make my beforeUpdate hook as follows:

    $this->addHook('beforeUpdate', function ($m, $data) {
        if (!isset($m->dirty['updatingSpouse']) && !isset($data['updatingSpouse']) &&
            (isset($m->dirty['spouse_id']) || isset($data['spouse_id'])))
        {
            if ($m->dirty['spouse_id'] != null)
            {
                $oldSpouse = new Person($m->persistence);
                $oldSpouse->tryLoad($m->dirty['spouse_id']);
                if ($oldSpouse->loaded())
                {
                    $oldSpouse['updatingSpouse'] = true;
                    $oldSpouse['spouse_id'] = null;
                    $oldSpouse->save();
                    $oldSpouse['updatingSpouse'] = false;
                    $oldSpouse->save();
                }
            }
            if ($data['spouse_id'] != null)
            {
                $newSpouse = new Person($m->persistence);
                $newSpouse->tryLoad($data['spouse_id']);
                if ($newSpouse->loaded())
                {
                    $newSpouse['updatingSpouse'] = true;
                    $newSpouse['spouse_id'] = $m['id'];
                    $newSpouse->save();
                    $newSpouse['updatingSpouse'] = false;
                    $newSpouse->save();
                }
            }
        }

This does work, but it seems awkward. Is there a better way to do this?

Also, a related question - am I doing a redundant isset check here? If $m->dirty[‘field’] is set is it guaranteed that $data[‘field’] will also be set?

Thanks for your assistance – I’m having a lot of fun developing useful applications using Agile Data/Agile UI.

#2

I think in order to do this, you must use the isDirty method. i.e. update the first spouse and ask for an update of the second ONLY if it is not already set as a spouse of the first one.

Also a good idea would be to use the afterUpdate hook for this.

#3

I thought about that, but the documentation says that the $data array of the fields that need to be changed is passed to beforeUpdate, but it doesn’t say that it’s passed to afterUpdate, so my assumption was that by the time you got to afterUpdate the dirty status of it was eliminated (since the update had already happened), and I therefore couldn’t tell whether or not it was the spouse field that actually changed and I wouldn’t know whether or not I needed to do anything. I couldn’t find any actual documentation on when dirty became false for a field, though, so I’m not sure. Is this defined somewhere?

#4

From my experience the dirty state is lost only for never_persist fields. For the others it works as good as beforeUpdate hook. But you can always try it yourself.