I think you have a mistake in your Carbon methods:
$today = $cDate->diffInSeconds();
So $today
will be the number of //seconds// until/since the start date. (Your conditional is only going to run within 10 seconds of start date. This is an extremely small window, so the code is probably never running.) You probably want diffInDays
. This will still measure accurately down to the second level, but will return its value as the number of days.
That said, I would suggest approaching this problem a little differently if you want to do it the more "Laravel" way.
It's certainly possible to make a system that would update DB values on access, but I would recommend against it. If you start showing the price in multiple views, you will have to make sure you are always running the same update function in every view. It's also very easy for a mistake to wreak havoc (if you accidentally run an update at a wrong interval it's hard to determine how you changed values, and you could easily modify a lot).
Instead I'd recommend using dynamic attributes on your Eloquent models. price
has such a regular formula, it really doesn't need to be in the database at all, and other values, like the date of the next price change and whether the product is expired, can also be determined automatically in the model instead of the controller:
class Product extends Model {
/* (your existing eloquent model code...) */
// This special array will automatically mutate your date columns into
// Carbon date objects, so you don't have to call Carbon::parse all the time
protected $dates = ['created_at', 'start_date', 'expires_at'];
// This is a custom accessor. It will run every time we try to
// get $product->price. https://laravel.com/docs/5.2/eloquent-mutators
public function getPriceAttribute()
{
// find the number of days since start_date, capped to a max of 9 days
$daysSinceStart = min($this->start_date->diffInDays(), 9);
// reduce the price by 10% every day
return $this->msrp * (1-($daysSinceStart / 10));
// (note that I leave the formatting to the front-end)
}
// This accessor returns the datetime of the next price change for use in a countdown timer.
public function getNextPriceChangeAttribute()
{
$daysSinceStart = $this->start_date->diffInDays();
return $this->start_date->copy()->addDays($daysSinceStart + 1);
}
// This accessor provides a boolean identifying whether 10 days have passed since the start.
public function getIsExpiredAttribute()
{
return $this->start_date->diffInDays() >= 10;
}
// This special array lists attributes that are added to product listings
// even when they don't exist in the underlying database. (the value is
// determined using our accessor method above)
protected $appends = ['price', 'next_price_change', 'is_expired'];
}
Then you can just use $product->price
, $product->next_price_change
, $product->is_expired
in your controllers and views without having to make updates or calculate them each time.
Wow thank you so much, I knew there was a better way to do that. i am really new as you can tell and i know that there are much better way to do stuff but i have to try my own in order to learn. I could not thank you enough for doing this, with this I can fix other issues I had in my code. Very much appreciated.
The reason I was looking to update the price in the database is because I have multiple areas in the website where I pull this price and since this is in the product model it will not pull in all the other controllers.
For example I need to pull the product on the front page, or in the category page or a related widget. Would it not be simpler to update the price at this point?
virgiltu said:
The reason I was looking to update the price in the database is because I have multiple areas in the website where I pull this price and since this is in the product model it will not pull in all the other controllers.
For example I need to pull the product on the front page, or in the category page or a related widget. Would it not be simpler to update the price at this point?
The code I suggested goes in your product's model, not the controller, so whenever something reads a product's price, that code should run. That's part of the reason I suggested it (and the beauty of Eloquent models) -- the code doesn't get duplicated everywhere.
There might be reasons to save the price. It isn't a wrong choice. But I think the safest plan in any case is to make sure that the prices are verified every time they are accessed.
Some model actions have events you can tie into (like "save" and "delete"), but fetch doesn't have an event, so //to me// the most logical place to ensure this happens is in an accessor.
I could not thank you enough for the explanation. I realized that it did bring the data in every time on my other screens.I pay for laracast but i did not see this in there. maybe i missed it.
Sign in to participate in this thread!
The Laravel portal for problem solving, knowledge sharing and community building.
The community