Home > database >  i want to change my API response to become array of array object in laravel
i want to change my API response to become array of array object in laravel

Time:02-10

i have a problem for the response, i want to change the response API because i need for my mobile APP, the feature have filter object based on date. So i hope you all can help me to solve the problem

i wanna change the response for my API

before:

{
    "tasks": [
        {
            "id": 7,
            "user_id": 1,
            "title": "gh",
            "date": "2022-02-10 13:05:00",
            "deskripsi": "gfh",
            "created_at": "2022-02-09T06:05:56.000000Z",
            "updated_at": "2022-02-09T06:05:56.000000Z"
        },
        {
            "id": 5,
            "user_id": 1,
            "title": "ghf",
            "date": "2022-02-17 16:05:00",
            "deskripsi": "fghf",
            "created_at": "2022-02-09T06:05:12.000000Z",
            "updated_at": "2022-02-09T06:05:12.000000Z"
        },
        {
            "id": 6,
            "user_id": 1,
            "title": "fgh",
            "date": "2022-02-17 18:05:00",
            "deskripsi": "gh",
            "created_at": "2022-02-09T06:05:40.000000Z",
            "updated_at": "2022-02-09T06:05:40.000000Z"
        }
    ]
}

here is the code for the response API above

return response([
            'tasks' => Task::where('user_id', auth()->user()->id)->where('date','>',NOW())->orderBy('date','asc')->get(),
        ],200);

and i want to change it my response API into this response

{
    "tasks": [
        {
            "date": "2022-02-10",
            "task": [
               {
                  "id": 7,
                  "user_id": 1,
                  "title": "gh",
                  "date": "2022-02-10 13:05:00",
                  "deskripsi": "gfh",
                  "created_at": "2022-02-09T06:05:56.000000Z",
                  "updated_at": "2022-02-09T06:05:56.000000Z"
               },
               {
                  "id": 7,
                  "user_id": 1,
                  "title": "gh",
                  "date": "2022-02-10 15:05:00",
                  "deskripsi": "gfh",
                  "created_at": "2022-02-09T06:05:56.000000Z",
                  "updated_at": "2022-02-09T06:05:56.000000Z"
               }
            ]
        },
        {
            "date": "2022-02-12",
            "task": [
               {
                  "id": 7,
                  "user_id": 1,
                  "title": "gh",
                  "date": "2022-02-12 13:05:00",
                  "deskripsi": "gfh",
                  "created_at": "2022-02-09T06:05:56.000000Z",
                  "updated_at": "2022-02-09T06:05:56.000000Z"
               }
            ]
        },
    ]
}

CodePudding user response:

Do groupBy on the resulting Collection from the query (see docs: https://laravel.com/docs/9.x/collections#method-groupby)

For example, you could do:

$tasksGroupedByDate = Task::where(.......)
    ->get()
    ->groupBy(fn (Task $task) => $task->date->format('Y-m-d'));

(Note: above uses PHP 7.4 arrow functions. Also, add a date cast on the date column in your Task model to be able to use ->format( directly on the date field)

The above code results to:

{
  '2022-01-01' => [
    { Task object },
    { Task object },
    { Task object },
  ],
  '2022-01-02' => [
    { Task object },
    { Task object },
    { Task object },
  ],
}

(used Task object for brevity, but that will be ['id' => 1, 'title' => 'Task name', .....])

To morph that to the structure you want, you can use map and then values to remove the keys and turn it back to an ordered array:

$tasksGroupedByDate->map(fn ($tasksInGroup, $date) => [
    'date' => $date,
    'task' => $tasksInGroup
])->values();

If you want to combine everything into one method chain:

return [
    'tasks' => Task::where(......)
        ->get()
        ->groupBy(fn (Task $task) => $task->date->format('Y-m-d'))
        ->map(fn ($tasksInGroup, $date) => [
            'date' => $date,
            'task' => $tasksInGroup
        ])
        ->values(),
];

CodePudding user response:

It sounds like you want to create a human friendly date field based on the date column, then group by it.

While solutions do exists to accomplish this at the database level, I believe you'd still need to loop around it again afterwards to get the hierarchy structure you're looking for. I don't think it's too complicated for PHP to loop through it.

My suggestion is as follows:

Before:

return response([
            'tasks' => Task::where('user_id', auth()->user()->id)
                ->where('date','>',NOW())->orderBy('date','asc')->get(),
        ],200);

After:

$out = [];
$tasks = Task::where('user_id', auth()->user()->id)
        ->where('date','>',NOW())->orderBy('date','asc')->get();

foreach($tasks as $task) {
    $date = strtok((string)$task->date, ' ');
            if (empty($out[$date])) {
                $out[$date] = (object)['date' => $date, 'task' => []];
            }
            $out[$date]->task[] = $task;
}

$out = array_values($out);

return response(['tasks' => $out], 200);

Note in the above I'm using the function strtok. This function might look new even to the most senior of php developers.... It's a lot like explode, except it can be used to grab only the first part before the token you're splitting on. While I could have used explode, since the latter part after the token isn't needed, strtok is better suited for the job here.

CodePudding user response:

$task = Task::where('user_id', auth()->user()->id)->where('date','>',NOW())->orderBy('date','asc')->get();

foreach($task as $item){
   $date[] = item->date;
   $result = Task::where('user_id', auth()->user()->id)->where('date','=', $date)->get();
}

return response([
   'tasks' => 
      ['date' => $date,
      'task' => $task]
],200);

maybe something like this

  • Related