Hi, I'm making a site in 2.3.1 and trying to put some code in Page::onBeforeWrite().
The problem is, onBeforeWrite always gets called multiple times - twice if I just click "save", four times if I click "save and publish".
Is this the normal behaviour? What can I do to just get it to run some code once?
Yeah this is making no sense to me at all...unfortunately your method doesn't entirely work for me since if I only make a change on one of the iterations it seems to get overwritten by later ones.
For example, I tried just adding "-test" to the URLSegment in onBeforeWrite, but if I use a static var to only do it once the change shows up in the sitetree table/cms but it it doesn't add -test to sitetree_live, so doesn't show up on the frontend. Without the static var filter I end up with things like -test-test on my URLSegment.
I did a dump of $this and compared all four times it ran. I'm wondering if it runs for every table attached to the object? The first one doesn't show the newly posted data or have any of the class-specific $db fields. It makes a new version number every time, though. The status attribute goes Published -> Saved (update) -> Published -> Published, and each time the changed and original arrays do or don't have different attributes but I'm not seeing a pattern.
So in short I don't know why it does this but it's stuffing up the probably-way-too complicated bit of hacking I was trying to do here :/
Have a look in LeftAndMain->save() - if you hit "Save and Publish" in the CMS, these four lines cause the record to be written:
$record = $record->newClassInstance( $newClass );
There's no easy way around this, as far as I can see we need to write at least twice. In case of the "-test-test" problem, you'll have that as well if the record persists a bit longer in memory than you think in different cases. The easiest solid way is to make sure you didn't add "-test" already I guess? You can also use getChangedFields() to detect if any fields have changed (which gets reset after each write call). So in case of the URL, you could just react in your onBeforeWrite() if the URL has actually changed.