Jump to content

Determine old vs. new value of field when saving


Jonathan Lahijani
 Share

Recommended Posts

I'm having trouble figuring out how to do this correctly.

Let's say I have a page with an ASM select field.  Let's say this ASM select field has values A, B and C selected.

Let's say the page is edited so that the ASM select field has C removed and then it is saved.

How do I determine specifically if C was removed and also display a custom notification if C was removed (in addition PW's regular save page notification)?

I've got my code to a point where it can determine if this field was changed, but not specifically what value were changed. Not sure how to do it.

Thank you.

  • Like 1
Link to comment
Share on other sites

Not tested but something simular would work I guess
 

$this->addHookAfter('Pages::saveReady', $this, 'hookPagesSave');

public function hookPagesSave(HookEvent $event) {
    // Modified page, already contains changes in memory, not yet in DB
    $page = $event->arguments('page');
    
    // If there is a change in your field
    if ($page->isChanged('name_of_you_field')) {
        
        // Page as it is in the DB
        $oldPage = $this->pages->get($page->id);
        
        // ... Now you could do your comparison old <-> new.
    }
}
Edited by Martijn Geerts
code corrected, honour goes to gebeer!
  • Like 6
Link to comment
Share on other sites

  • 6 months later...

Not tested but something simular would work I guess

$this->addHookAfter('Pages::saveReady', $this, 'hookPagesSave');

public function hookPagesSave(HookEvent $event) {
    // Modified page, already contains changes in memory, not yet in DB
    $page = $event->arguments('page');
    
    // If there is a change in your field
    if ($page->trackChange('name_of_you_field')) {
        
        // Page as it is in the DB
        $oldPage = $this->pages->get($page->id);
        
        // ... Now you could do your comparison old <-> new.
    }
}
if ($page->trackChange('name_of_you_field')) {...}

got triggered for me on every page save, no matter if the value of my field had changed or not.

Changing it to

if ($page->isChanged('name_of_you_field')) {...}

brought the desired result.

See also $page->isChanged("field") in API cheat sheet

  • Like 4
Link to comment
Share on other sites

In Martijn's hook, the $oldPage retrieval will return the same exact copy as $page, so it won't be possible to compare them since you'll be comparing the same page instance. What you'd want to do instead is retrieve a fresh copy of the page, then you should have two different instances of the same page to compare: 

$oldPage = $this->wire('pages')->getById($page->id, array(
  'cache' => false, // don't let it write to cache
  'getFromCache' => false, // don't let it read from cache
));

I think you'll need the dev branch for this, as the 'getFromCache' option is not in PW 2.6.1 if I recall correctly. In 2.6.1 or earlier, I think that the following would work, but is not quite as efficient:

$this->wire('pages')->uncache($page);
$oldPage = $this->wire('pages')->get($page->id); 
  • Like 2
Link to comment
Share on other sites

I had the presumption that Pages::saveReady hold the values from the to be saved page (runtime) and not the value out of the database.

That's correct. PW tries really hard not to keep multiple copies of the same page in memory at once, which is why you have to make it force-reload a fresh copy from the DB if you want to know what the page looked like before changes were made to it. 

Link to comment
Share on other sites

Nope, it would give you the same copy that you already have. Unless something cleared the page cache between the time you loaded $page and the time you did your $pages->get(). PW clears the page cache after every save() or delete(), so if you found it was working in your case then chances are there was a save() that occurred after you loaded $page, but before you tried to retrieve $oldPage. 

  • Like 2
Link to comment
Share on other sites

In Martijn's hook, the $oldPage retrieval will return the same exact copy as $page, so it won't be possible to compare them since you'll be comparing the same page instance. What you'd want to do instead is retrieve a fresh copy of the page, then you should have two different instances of the same page to compare: 

$oldPage = $this->wire('pages')->getById($page->id, array(
  'cache' => false, // don't let it write to cache
  'getFromCache' => false, // don't let it read from cache
));

I did try this and it did not work, because getById returns a PageArray, not a Page object in spite of the get part in the method name. Using something like first() on the returned result seems to give you the cashed (changed) version of the page. But there is a getOne option that managed to do the trick. So I could only get it to work like this:

$oldPage = $this->wire('pages')->getById($page->id, array(
  'cache' => false, // don't let it write to cache
  'getFromCache' => false, // don't let it read from cache
  'getOne' => true, // return a Page instead of a PageArray
));
  • Like 6
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...