Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We're retiring the forums!

The SilverStripe forums have passed their heyday. They'll stick around, but will be read only. We'd encourage you to get involved in the community via the following channels instead:

Data Model Questions /

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

onBeforeWrite called multiple times

Go to End

10 Posts   5415 Views

Nathan Cox

Community Member, 99 Posts

9 May 2009 at 3:43pm

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?


Forum Moderator, 4102 Posts

10 May 2009 at 6:24am

Yes! I made a post about this a while back, as well. Annoying, isn't it? My solution was really crude. I set a static class variable to choke the onBeforeWrite() after the first execution.

static $has_written = false;

public function onBeforeWrite()
if(!self::$has_written) {
// do stuff
self::$has_written = true;

I'd really like more information about it, though, cause as you can see, it's a total hack and should not be necessary.

Nathan Cox

Community Member, 99 Posts

10 May 2009 at 3:14pm

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 :/


Forum Moderator, 801 Posts

11 May 2009 at 8:44pm

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.


Community Member, 791 Posts

11 June 2009 at 8:42pm


Just bumped into this myself just now. Interesting bug.

Someone made a ticket for this already ?

Ben Gribaudo

Community Member, 181 Posts

12 June 2009 at 3:40am

It would be nice for this issue to be fixed!


Community Member, 165 Posts

2 November 2009 at 11:37am

I'm also having this trouble, would be good if there was a fix. Any updates?




Community Member, 283 Posts

6 November 2009 at 10:41am

Just ran into this and am successfully using UncleCheese's hack. Effective!

Go to Top