I have a custom module, on EVENT_BEFORE_SAVE
I am looping through a matrix field, this matrix field has a block which has an entry field, a number field and a lightswitch (to know if this block has been processed - more on this below).
When saving the entry (containing the matrix field) I am currently looping through all the matrix blocks, getting the value form the numbers field and updating a field in the related entry from the entry field. The related entries are then all resaved.
On successful save for each related entry I want to update each the matrix block lightswitch field, from the original entry, to indicate that the related entry was updated and resaved. If there were any errors saving this lightswitch field would not be updated, and the entry can be reprocessed in the future.
The issue I am having is, on the successful entry save of the matrix entry field Entry, the lightswitch field is not being updated.
You can see where I am trying to update the lightswitch field in the current block here (Full code is below)
if (Craft::$app->elements->saveElement($getRelatedEntry))
{
// Update lightswitch field in current block in Entry
$block->setFieldValue('stockAdded', 1);
// Save block
Craft::$app->elements->saveElement($block);
}
I would be interested to see how others may handle this situation, whether it may be possible to hold off going past EVENT_BEFORE_SAVE
until it require it to, or if this process could be handled differently and more effectively.
Here is the code I am using, I have cleaned up a few bits for simplicity.
foreach ($entry->matrixField->blockProcessed(0)->all() as $block) {
$processed = $block->blockProcessed;
// Check to see if this has been processed already
if ($processed) {
// Do nothing
return;
}
// Get entry
$relatedEntry = $block->blockEntry->one() ?? null;
if (!$relatedEntry) {
// Entry does no exist - Do nothing
return;
}
// Get ID from the related Entry
$relatedEntryId = $relatedEntry->id;
// Get value to from block
$value = $block->blockValue;
// Get product entry
$getRelatedEntry = Entry::find()->id($relatedEntryId)->one() ?? null;
// Check of entry exists and value is greater than zero
if ($getRelatedEntry && $value > 0) {
// Get current value
$currentValue = $getRelatedEntry->value;
// New stock amount
$newValue = $currentValue + $value;
// Update stock level
$getRelatedEntry->setFieldValue('value', $newValue);
// Save product entry
if (Craft::$app->elements->saveElement($getRelatedEntry))
{
// Update lightswitch field in current block in Entry
$block->setFieldValue('blockProcessed', 1);
// Save block
Craft::$app->elements->saveElement($block);
}
}
}
Update
It was pointed out that the block was not being saved before the entry was saved, so it lost any data. being passed I have updated the code examples above to include the change.
This partially solved the issue, the other part of the issue seems to be with the propagation of the matrix blocks to the new entry which I need to overcome.
Saving the entry now, with the block saving code (Craft::$app->elements->saveElement($block);
), causes the entry to lose the block data until the page is refreshed.
The behaviour seems to show the updated block data on the initial save, when viewing the entry it shows the blocks with the lightswitch field turned on, however when if the entry is saved again it loses the matrix field block data.
What is the best way to continue saving the entry and propagate the updated matrix blocks. Would it be best to move this to EVENT_AFTER_PROPAGATE
or am I missing something when saving the block initially with the updated data?
##Update 2
After some investigating the issue with the lost matrix block was resolved moving to using EVENT_AFTER_PROPAGATE
, running the code at this point and only saving the block after the new data was passed solved the whole issue I was having.