Jump to content

Get previous template/field properties on saving


MarkE
 Share

Recommended Posts

FWIW I have made a little work-round that saves $template->getExportData() as a session var on 'ready' then compares it with the changed value, hooked in 'saved'. It seems to work, but there must be a less clumsy way. trackChanges etc is not very helpful.

  • Like 1
Link to comment
Share on other sites

  • 1 month later...

Just bumping this in case anyone has any ideas. As stated above, my work-round is rather clumsy and inefficient. Surely there must be an easier way?!

EDIT: I notice that WireSaveableItems has a hookable method ___saved(Saveable $item, array $changes = array()) but I can't find anything calling it with the $changes parameter set.

Link to comment
Share on other sites

So here's a (hopefully better and working) solution. Add the following as a hook to (i.e. new method for) WireSaveableItems:

	public function getFreshSaveableItem($event) {
		$saveables = $event->object;
		$item = $event->arguments(0);
		$database = $this->wire()->database;
		$sql = $saveables->getLoadQuery()->getQuery();
		$query = $database->prepare($sql);
		$query->execute();
		$rows = $query->fetchAll(\PDO::FETCH_ASSOC);
		$newItem = null;
		if($item) {
			foreach ($rows as $key => $val) {
				if ($val['id'] == $item->id) {
					$row = $rows[$key];
					$newItem = $saveables->initItem($row);  // there should be only one matching item
					break;
				}
			}
		}
		$event->return = $newItem;
	}

This returns the item as it is in the database, so if you call (say) wire('fields')->getFreshSaveableItem($myfield) in a beforeSave hook, you will get the version of $myfield that is in the database - i.e before it is saved and can compare it with the version about to be saved.

But if you want to use this, test it out well first!

Maybe someone else can come up with something better (or even a PR for the core?!)

Link to comment
Share on other sites

I just tested this:

//ready.php


/* Turn on tracking of changed values for all Templates.
 * Couldn’t find a hook for this, so I’m just iterating
 * all templates on every request. Should be fine?
 * Both calls to setTrackChanges() are  needed. */
foreach (wire('templates') as $template) {
    /** @var Template $template */
    $template->setTrackChanges(Wire::trackChangesValues);
    $template->setTrackChanges(true);
}


/* Dump tracked changes when Templates are saved, or
 * do whatever with them */
wire()->addHookBefore('Templates::save', function (HookEvent $event) {
    /** @var Template $template */
    $template = $event->arguments(0);

    bd($template->getChanges(true));
    //var_dump($template->getChanges(true));
});

This doesn’t get changes to a template’s fields, but you can probably do something similar with Fieldgroups and Fields themselves.

Link to comment
Share on other sites

1 hour ago, Jan Romero said:

I just tested this:

That seems to work and might be sufficient if you just want to know if there are any changes. The test that I did - adding a field to a template - gave a curious array of changes in the bar dump, viz:

array
'compile' => array
	0 => 3
'noParents' => array
	0 => ''

i.e. nothing about the field that had been added. I have no idea why this is.

On the other hand, my getFreshSaveableItem() method returns the complete template before any changes, so includes the related fieldgroup. However it may be slower - I haven't benchmarked them.

Link to comment
Share on other sites

Yes, it’s not going to pick up changes to the Fields, because behind the scenes you’re actually adding the Field to the Template’s Fieldgroup. Can’t figure out how to get added fields, but getting removed fields seems to work reliably:

foreach(wire('templates') as $template) {
    /** @var Template $template */
    $template->setTrackChanges(Wire::trackChangesValues);
    $template->setTrackChanges(true);
    $template->fieldgroup->setTrackChanges(Wire::trackChangesValues);
    $template->fieldgroup->setTrackChanges(true);
}


wire()->addHookBefore('Templates::save', function (HookEvent $event) {
    /** @var Template $template */
    $template = $event->arguments(0);

    bd($template->getChanges(true));
});


wire()->addHookBefore('Fieldgroups::save', function (HookEvent $event) {
    /** @var Fieldgroup $fieldgroup */
    $fieldgroup = $event->arguments(0);

    bd($fieldgroup->getChanges(true)); //says NULL for added fields, because the previous value of the added field was no field, works well for removed fields
    bd($fieldgroup->getItemsAdded()); //gives all fields in the set for some reason
    bd($fieldgroup->removedFields); //this seems to work well
});

If you have a use case for this there may be opportunities for PRs here. For example it doesn’t seem reasonable to me that removing a field tracks the change as "removed:<fieldname>" (plus the field itself as the old value) while adding one tracks as "add" without the field name (and no old value, because it was an add).

  • Like 1
Link to comment
Share on other sites

Thanks for all the ideas @Jan Romero . Personally I got a bit frustrated with TrackChanges because it seems to be a bit random about what it records - for pages as well as fields etc. That’s why I started using getFresh() for pages with a home-built compare function because it gave me full control and understanding. So my idea was to do something similar for fields and templates (and fieldgroups) - the code above is my attempt at this and no doubt can be improved. The getFresh() for pages is hugely more complex!

Nevertheless, I agree that a more robust and consistent TrackChanges is desirable. 

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...