0

New to Eloquent and having a puzzling issue with regards to a return value from a method. The when() method works as expected for two of three almost identical filters, but the third one returns a results set that is formatted differently.

I am able to filter a collection of results into two separate arrays of objects using the when() method. But a third, identical filter ($pastBooks) used on the same collection returns an indexed object instead of an array of objects. All data within the database is standardized and uses the same carbon date format. I'm stumped, and would be grateful for any assistance.

$bookings = Booking::leftJoin('classes', 'bookings.class_id', '=', 'classes.class_id')
                        ->leftJoin('users', 'bookings.user_id', '=', 'users.id')
                        ->get(['bookings.booking_id', 'users.name','classes.class_id',
                               'classes.class_name', 'classes.class_date', 'users.phone','users.email']);  

$todayBook = $bookings->where('class_date', \Carbon\Carbon::today());

$thisWeekBooks = $bookings->where('class_date', '>', \Carbon\Carbon::today());

$pastBooks  = $bookings->where('class_date', '<', \Carbon\Carbon::today());

return(['today' => $todayBook, 'past' => $pastBooks,'thisWeekBooks' => $thisWeek]);

//Results

 {
 today: [ ],
 past: {
 11: {
 booking_id: 220,
 name: "trial",
 class_id: 8,
 class_name: "Intermediate",
 class_date: "2020-11-30 21:47:23",
 phone: 12356789,
 email: "trial@gmail.com"
 },
 12: {
 booking_id: 212,
 name: "trial",
 class_id: 9,
 class_name: "one-to-one",
 class_date: "2020-12-30 21:47:23",
 phone: 12356789,
 email: "trial@gmail.com"
  },
 13: {
 booking_id: 213,
 name: "trial",
 class_id: 9,
 class_name: "one-to-one",
 class_date: "2020-12-30 21:47:23",
 phone: 12356789,
 email: "trial@gmail.com"
 }
 },
 thisWeek: [
 {
 booking_id: 207,
 name: "trial",
 class_id: 7,
 class_name: "beginner",
 class_date: "2021-02-17 21:47:23",
 phone: 12356789,
 email: "trial@gmail.com"
 },
 {
 booking_id: 208,
 name: "trial",
 class_id: 7,
 class_name: "beginner",
 class_date: "2021-02-17 21:47:23",
 phone: 12356789,
 email: "trial@gmail.com"
 }
 ]
 }
  • I got into the same problem today, I used sortBy() on a collection and that index was returned. What I did was `foreach ($collection->sortBy('type') as $key => $value) { $response[] = $value; }` – Martzy Feb 17 '21 at 13:51
  • You can also see [this question/answer](https://stackoverflow.com/questions/42182919/laravel-collection-converts-array-to-object/42183156#42183156). While the answer is basically the same, the question was different, so I didn't mark it as a duplicate. – patricus Feb 17 '21 at 14:07
  • @patricus Thanks, what I was looking for! – Martzy Feb 17 '21 at 14:15
  • I went ahead and marked this as a duplicate of the other question. The `where()` on the collection is just a front for `filter()`, so it's basically the same thing. – patricus Feb 17 '21 at 14:28

2 Answers2

1

They're all returning the same thing, you're just seeing a difference due to the JSON conversion.

JSON arrays only support proper numerical, 0-based, sequentially indexed arrays. If the index is not numeric, not 0-based, or not sequential, the array will be represented as an object.

Your data is essentially this:

[
    'today' => [ ],
    'past' => [
        11 => Object11,
        12 => Object11,
        13 => Object11,
    ],
    'thisWeek' => [
        0 => Object0,
        1 => Object1,
    ],
]

Since the keys of your thisWeek collection are numeric, 0-based, and sequential, JSON can represent this as an array of objects. However, though the keys in your past collection are numeric and sequential, they don't start at 0, so this array will be represented as an object with numeric properties.

You can use the values() method on your collection to rekey your collections with numeric 0-based sequential keys.

return([
    'today' => $todayBook->values(),
    'past' => $pastBooks->values(),
    'thisWeek' => $thisWeek->values(),
]);
patricus
  • 59,488
  • 15
  • 143
  • 145
  • Thanks for that very informative answer, Patricus. Those values are indeed returned when using the values() method. Do you know why the keys in that particular collection are not numeric and sequential? I don't recall having altered them in any way that would cause this to be the case. – monkeytrick Feb 17 '21 at 14:10
  • @monkeytrick The `where()` method does not rekey the new collection after filtering it. The keys you get are the same keys that those items had in the original collection. – patricus Feb 17 '21 at 14:26
  • Ah, I see. That's very insightful and, I suspect, will help avoid headaches further down the road. Many thanks, Partricus! – monkeytrick Feb 17 '21 at 14:30
0

As I know get function must be at the end

like from this

$bookings = Booking::leftJoin('classes', 'bookings.class_id', '=', 'classes.class_id')->leftJoin('users', 'bookings.user_id', '=', 'users.id')->get(['bookings.booking_id', 'users.name','classes.class_id', 'classes.class_name', 'classes.class_date', 'users.phone','users.email']);  

$todayBook = $bookings->where('class_date', \Carbon\Carbon::today());

to this

$bookings = Booking::leftJoin('classes', 'bookings.class_id', '=', 'classes.class_id')->leftJoin('users', 'bookings.user_id', '=', 'users.id');  

$todayBook = $bookings->where('class_date', \Carbon\Carbon::today())->get(['bookings.booking_id', 'users.name','classes.class_id', 'classes.class_name', 'classes.class_date', 'users.phone','users.email']);