Групповые отношения с детьми в ларавеле

#php #laravel #eloquent

Вопрос:

У меня есть два стола

 properties (id, name, address, created_at, updated_at)
bookings (id, property_id, booking_date, total_amount, comission, created_at, updated_at)
 

Property.php модель имеет такое отношение

 public function bookings()
{
    return $this->hasMany('AppModelsAirbnbBooking','property_id','id');
}
 

Я хочу вернуть ответ JSON (или красноречивую коллекцию), как показано ниже

 [{
  "property_id": 1,
  "address": "Property ABC",
  "bookings": {
    "2021": {
      "Jul": [
        {
          "id": 23,
          "property_id": 1,
          "booking_date": "30-07-2021",
          "total_amount" : "220.00"

        },
        
      ]
    }
  }
}]
 

Примечание: Требования являются

  1. Все данные о свойствах должны быть там.
  2. У свойств должен быть ключ бронирования, который содержит записи по годам, такие как 2020, 2021 и т. Д., Затем год снова делится на ключи месяца, такие как январь, ФЕВРАЛЬ и т. Д., Затем в месяце должны быть все данные за месяц из таблицы бронирования, используя столбец booking_date.
  3. Вместо цикла for я хотел использовать groupBy на уровне запросов, но не очень хорошо знаком с тем, как построить эту структуру.

Что я пытался

 $query = Property::with(['bookings' => function($query) use($startDate, $endDate){
                            $query->whereDate('booking_date', '>=', $startDate)
                            ->whereDate('booking_date', '<=', $endDate);
                            ->groupBy('booking_date');
                        }])->get();
 

Приведенный выше код не работает.
Кроме того, я попробовал использовать запросы к БД, которые также не работают.

        $query = DB::table('properties')
                        ->join('bookings', 'properties.id', '=', 'bookings.property_id')
                        ->select([
                            'properties.id as property_id',
                            'properties.name as property_name',
                            'properties.address as property_address',
                            'bookings.id as booking_id',
                            DB::raw('YEAR(bookings.booking_date) booking_year'),
                            DB::raw('MONTH(bookings.booking_date) booking_month'),
                        ])
                        ->whereDate('bookings.booking_date', '>=', $startDate)
                        ->whereDate('bookings.booking_date', '<=', $endDate)
                        ->orderBy('booking_year', 'booking_month')
                        ->get();
 

I was able to achieve it with for loop, after getting all the properties with bookings.

 $i = 0;
        $array[$i]['bookings'] = [];
        foreach($query as $property){
            $array[$i]['property_id'] = $property->id;
            $array[$i]['address'] = $property->address;
            foreach($property->bookings as $booking){
                $year = date('Y', strtotime($booking->booking_date));
                $month = date('M', strtotime($booking->booking_date));
                $array[$i]['bookings'][$year][$month][] = $booking;
            }
            $i  ;
        }
        return $array;
 

I wanted to improve code performance by not using for loop, as the properties are quite large in numbers, so wanted to use groupBy at the query level, but not much familiar with how to properly use it.

Any guidance would be highly appreciated.Thanks