I took over an existing project and have to adjust some parts of it. There is one problem with a repeater field.
The CMS has pages with some kind of like products (saved as repeaters) and there is a weekly cron that makes copies of those pages. As I can see there is a hook event before the pages are saved. The hook calculates the sum of those products (repeater fields) and saves it to another field the just copied page. Problem is the hook is executed twice and thus the sum doubled.
An example
Page A
- Repeater field product A1 and price 10 USD
- Sum field: 10 USD
Now cron makes copy of page A
Page A copy
- Repeater field product A1 and price 10 USD
- Sum field: 20 USD
This is from the cron task
// Create a new page
$p = new Page();
$p->of(false);
$p->template = 'cables';
$p->parent = $pages->get('/cables/top/');
$p->name = 'c_23B14__' . date('H:i:s') . uniqid();
$p->title = 'Preview ' . uniqid();
$p->body = $order->body;
$p->due = $today_midnight;
$p->history = 'Created: ' . date('Y-m-d H:i:s') . ' - ' . $order->title;
$p->removeStatus('published');
$p->addStatus('unpublished');
$p->save();
wire('log')->save('cron_1_friday', 'Page created (' . $p->id . ')');
// Copy items
foreach ($pushToInvoice as $copy_item) {
$new_item = $p->document_items->getNew();
$new_item->repeater_matrix_type = 1;
$new_item->of(false);
$new_item->title = $copy_item->title;
$new_item->unit = $copy_item->unit;
$new_item->quantity = $copy_item->quantity;
$new_item->price_per_unit = $copy_item->price_per_unit;
$new_item->discount = $copy_item->discount;
$new_item->tax = $copy_item->tax;
$new_item->options = $copy_item->options;
$new_item->due = strtotime('+ ' . $copy_item->recurring->settings->value . ' months', $copy_item->due);
$new_item->recurring = $copy_item->recurring;
$new_item->price = $copy_item->price;
$new_item->price_total = $copy_item->price_total;
$new_item->save();
$p->document_items->add($new_item);
$p->save();
wire('log')->save('cron_1_friday', 'Item added (' . $new_item->id . ')');
}
$p->save();
and this is the hook event
wire()->addHookBefore('Pages::saveReady', function(HookEvent $event) {
/** @var Page $page */
$page = $event->arguments(0);
if ($page->template == 'cables' || $page->template == 'tubes') {
$total_net = 0;
$total_gross = 0;
foreach ($page->document_items as $child) {
if (!$child->options->optional) {
$item_net = ($child->quantity * $child->price_per_unit) * (1 - ($child->discount / 100));
$total_net += $item_net;
bd($total_net);
if ($child->tax->id) {
$item_gross = $item_net * ( ( (int)$child->tax->settings->value / 100) + 1 );
$total_gross += $item_gross;
}
}
}
// Set price
$page->price = $total_net;
$page->price_total = $total_gross;
$event->arguments(0, $page);
}
});
I added the bd() and can see it is executed twice.
What's really confusing, even if it gets executed twice the hook event should always just find one item in it and it sums up to just 10 USD.
But I have now idea how this works. It worked with almost the same code before fine, but it was changed from another repeater field (guess it was Page table).