Laravel Collection Date comparison

Oskar Jedvert picture Oskar Jedvert · Nov 19, 2015 · Viewed 19.6k times · Source

Alright so I have been looking for hours for an answer but can't seem to find one. I have an array of "orders" all for different dates. I get all of the orders for this week, this should not be an issue, then I want to a tab for each day of the week.

What I have tried so far is this:

$dinnerOrders->where('date','>',$date)->where('date','<', $date->endOfDay())->sortBy('created_at');

Where $date is :

$dt = Carbon\Carbon::create()->startOfWeek();
Carbon\Carbon::setTestNow($dt);
$date = new Carbon\Carbon('this ' . $day);

And $dinnerOrders are get by:

$dinnerOrders = collect([]);
foreach($restaurant->dinners as $dinner) {
    foreach($dinner->orders as $order) {
        $dinnerOrders[$order->id] = $order;
    }
 }

The dates seem correct and it words in sql. Is this not working because $dinnerOrders is a collection?

What I'm getting is nothing, i.e an empty set, despite it working in mysql terminal.

So what I'm asking is perhaps, can you do a date comparison on a collection? If so, how?

Answer

patricus picture patricus · Nov 19, 2015

Note: This answer is specific to Laravel <= 5.2. Laravel 5.3 updated the where() method on the Collection to match the query builder, so it now accepts an operator.


As you state in your question, $dinnerOrders is a Collection, not a query. The where() method on the Collection works a little differently.

For Collections, the where() method does not accept an operator. It only does equality comparisons. The first parameter is the key, the second is the value, and the third is a boolean to flag a loose comparison (==) vs a strict comparison (===).

What you're looking for is the filter() method. You pass in a Closure that does your date comparison. If the Closure returns true, the item stays in the Collection. If it returns false, the item is removed from the Collection. Something like this (just an example, the logic may need to be tweaked):

$dinnerOrders = $dinnerOrders->filter(function ($item) use ($date) {
    return (data_get($item, 'date') > $date) && (data_get($item, 'date') < $date->endOfDay());
});

Post Question Edit

Based on the code provided in your edit, I'm guessing that a restaurant hasMany dinners, and a dinner hasMany orders. If this is correct, you can setup a relationship stating that a restaurant hasMany orders through dinners:

Restaurant.php:

public function orders() {
    // restaurant has many orders through dinners
    $this->hasManyThrough('App\Order', 'App\Dinner');
}

With this relationship setup, you could then get your information using the query builder:

$dinnerOrders = $restaurant->orders()->where('date','>',$date)->where('date','<', $date->endOfDay())->get();