Jump to content
valan

smart hook on field save

Recommended Posts

There is a need to send mail when (1) some fields (2) in some template (3) at some page (4) were changed from "one value" to "another value" (5) via API (e.g. not only from admin).

 

Questions:

1. Please could you help with right hook for that"Fields::save"?

2. How to get $page from hook method, e.g. $page where field is planned to be changed?

3. Finally, would this piece of code work? - specifically getting old and new values, plus messaging to admin (in case changes are not from API)

    public function init()
    {
        $this->addHookAfter("Field::save", $this, "validateAndMail");
    }

    public function validateAndMail($event)
    {
        $field = $event->object;

        if($field->name == 'my_field')
        {
            $page = ? // some code here to get page where this field is planned to be saved

            $is_this_page = $page->id === 12345; // needed page
            $is_this_template = $page->template->name === 'my_template'; // needed template

            $oldValue = $page->get($field->name);
            $newValue = $field->value;

            if($oldValue === "foo" && $newValue==="bar" && $is_this_page && && $is_this_template)
            {
                my_mail_func($page, $oldValue, $newValue);
                $this->message($this->_("$newValue !!!")); // would it work in case of changes from admin?
            }
        }
    }

Share this post


Link to post
Share on other sites

First of all your hooked function is the wrong one. Field::save is called when a fieldsettings should be saved, but not when fielddata should be saved. You should rather use Page::saved, which is called right after a page is saved.

$this->addHookAfter('Pages::saved', $this, 'afterSaved'); 

/**
 * DocBlock from wire/core/Pages.php
 * @param Page $page The page that was saved
 * @param array $changes Array of field names that changed
 * @param array $values Array of values that changed, if values were being recorded, see Wire::getChanges(true) for details.
 */
public function afterSaved($event) {
    $page = $event->arguments(0); 
    $changes = $event->arguments(1);
    $values = $event->arguments(2);

    // Check for your conditions and send email
}

Share this post


Link to post
Share on other sites

As far as I understand "Pages::saved" is called on $page->save().

Is it also called when field is saved from API, e.g. called on $page->save($field, $value) and on $page->setAndSave($field, $value)?

Share this post


Link to post
Share on other sites

I guess not. If it is something like Pages::saveReady, it is only called on $page->save() but not on $page->save($field, $value).

Share this post


Link to post
Share on other sites

There's Pages::saved, which is called on every $pages->save() execution and there's Pages::savedField, which is called on every $pages->saveField() execution. You probably need to hook both, to cover all posibilities.

  • Like 2

Share this post


Link to post
Share on other sites

@Ivan, thanks - I missed somehow intro of conditional hooks - looks like syntax sugar)

@LostKobrakai, thanks for advice with two hooks - it is not so obvious.

Two Qs left:

1. How to get old and new values from Pages::savedField? I see only $page and $field among args... sorry still can't catch logic here.

2. What if you want to check new field value - compare it with old value and prevent saving on some condition? e.g. Which hook to use in this case? and I guess set it with addHookBefore?

Again - I'm saving from API with $page->save($field) and $page->save()

Share this post


Link to post
Share on other sites

@LostKobrakai: But Pages::savedField does have different arguments to Pages::saved. So you would probably have to write different code for the hook functions?

@valan: I managed to solve similar task hooking FieldtypeMulti::savePageField. This works for something derived from FieldtypeMulti. To hook fieldtypes extending Fieldtype class you can hook Fieldtype::savePageField.

Here is the code:

public function init() {
	$this->addHookBefore('FieldtypeMulti::savePageField', $this, 'saveFieldtypeMulti');
}

public function saveFieldtypeMulti($event) {
	// Get current page and field
	$page = $event->arguments[0];
	$field = $event->arguments[1];
	
	// Perform all the check to execute only when needed
	if ($page->template != 'your-template') return;
	if ($field->name != 'your-field') return;
	
	// Get the instance of the page from db as it was before the edit session.
	$pageBeforeChange = $this->wire('pages')->getById($page->id, array(
		'cache' => false,
		'getFromCache' => false,
		'getOne' => true,
	));
	
	if($page->your-field == "now-value" && $pageBeforeChange->your-field == "before-value") {
		/* send email */ 
	}
}

This should work whether you save the page or just the field.

  • Like 1

Share this post


Link to post
Share on other sites

2. What if you want to check new field value - compare it with old value and prevent saving on some condition? e.g. Which hook to use in this case? and I guess set it with addHookBefore?

If you only want to prevent saving the current field, you probably could modify the code above to be hooked before FieldtypeMulti::savePageField and add something like this in the end:

if($page->your-field == "now-value" && $pageBeforeChange->your-field == "before-value") {
	$event->replace = true;
}

This should replace the whole FieldtypeMulti::savePageField and prevent the field from being saved. Not tested. No guarantees :).

  • Like 1

Share this post


Link to post
Share on other sites

Ivan, thank! Just tested code - works perfectly.

Share this post


Link to post
Share on other sites

One more point - FieldtypeMulti extends Fieldtype, so hook to Fieldtype::savePageField catches both events.

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...