This issue is quite strange because of its illogicality. Here is my flow of creating a model:
Create model via mass assignment -> catch 'created' event in the observer -> calculate additional fields and update the newly created model.
Two out of three steps are working properly: I am able to catch the created event, but when it comes to saving the model something strange is happening. For instance, my test is running endlessly or it returns code -1. No errors, no stack trace, nothing. Here is my observer's code:
<?php
namespace App\Observers;
use App\Models\AdPrice;
class AdPriceObserver
{
/**
* Handle the models ad price "created" event.
*
* @param \App\Models\AdPrice $adPrice
* @return void
*/
public function created(AdPrice $adPrice)
{
$adPrice->update([
'incremental_diff' => $this->computeIncrementalDiff($adPrice),
'absolute_diff' => $this->computeAbsoluteDiff($adPrice)
]);
}
/**
* Handle the models ad price "updated" event.
*
* @param \App\Models\AdPrice $adPrice
* @return void
*/
public function updated(AdPrice $adPrice)
{
$adPrice->update([
'incremental_diff' => $this->computeIncrementalDiff($adPrice),
'absolute_diff' => $this->computeAbsoluteDiff($adPrice)
]);
}
/**
* Compute the incremental price difference.
*
* @param \App\Models\AdPrice $adPrice
* @return float|null
*/
protected function computeIncrementalDiff(AdPrice $adPrice)
{
/* @var \Illuminate\Support\Collection $prices */
$prices = $adPrice->priceable->prices()->pluck('price');
if ($prices->count() < 2) {
return null;
}
$diff = ($prices[0] - $prices[1]) / $prices[1];
return number_format($diff * 100, 2);
}
/**
* Compute the absolute price difference.
*
* @param \App\Models\AdPrice $adPrice
* @return float|null
*/
protected function computeAbsoluteDiff(AdPrice $adPrice)
{
/* @var \Illuminate\Support\Collection $prices */
$prices = $adPrice->priceable->prices()->pluck('price');
if ($prices->count() < 3) {
return null;
}
$diff = ($prices[0] - $prices->last()) / $prices->last();
return number_format($diff * 100, 2);
}
}
P.S. I am not including any other code(like observer registration in the service provider, etc.) because everything else works as it should.
P.S.S. The incremental_diff & absolute_diff fields are nullable and of type float. Also, they are cast to float in the model's file.
Your issue comes from an infinite recursion because of your update hook which call itself:
Edit: To fix this, I would set attributes manually in updating hook, btw you won't get an infinite loop.
You have an infinite update loop in the updated method of your observer.
Try something like this:
$adPrice->withoutEvents(function () use ($adPrice) {
$adPrice->update([
'incremental_diff' => $this->computeIncrementalDiff($adPrice),
'absolute_diff' => $this->computeAbsoluteDiff($adPrice)
]);
});
Oh, I haven't even noticed that recursion... Thanks!
Most helpful comment
Your issue comes from an infinite recursion because of your update hook which call itself:
And so on...
Edit: To fix this, I would set attributes manually in
updatinghook, btw you won't get an infinite loop.