ZetIndex_Ram
@ZetIndex_Ram

Как правильно работать с JsonResource в Laravel?

Коллеги, прошу вашей помощи! ¯\(ツ)/¯

Пишу я backend REST-api составляющую для одного проекта.

У меня есть api-маршрут domain.ru/api/offices, который должен возвращать список офисов и сотрудников (employees), трудящихся в каждом офисе.

Я создал OfficeResource и OfficeCollection для получения одного и многих офисов соответственно, также приведу код EmployeeResource

OfficeResource
return [
            "id" => $this->id,
            "code" => $this->code,
            "address" => $this->address,
            "employees" => new EmployeeCollection($this->employees),
            "created_at" => $this->created_at
];


EmployeeResource
return [
            "id" => $this->id,
            "name" => $this->name,
            "office" => $this->office
];


Для коллекций я просто создал с помощью artisan-интерфейса EmployeeCollection и OfficeCollection и ничего там не менял (ну как всегда делается) ¯\(ツ)/¯

код api.php
Route::get('offices', function (Request $request) {
    $office_collection = new OfficeCollection(Office::all());
    foreach ($office_collection as $office) {
        foreach ($office->employees as $employee) {
            unset($employee['id_office']);
        }
    }
    return response()->json([
        "status" => true,
        "response" => $office_collection,
    ], 200);
});


Так вот в чем проблема, у меня есть роут domain.ru/api/employees, который должен возвращать всех сотрудников и офис каждого сотрудника, в котором он работает Но также у меня есть роут domain.ru/api/offices, который возвращает офисы и сотрудников, работающих в них

Просто в роуте domain.ru/api/employees я должен включать офис в Json-ответ, а в роуте domain.ru/api/offices офис будет как бы "главным" и в него будет входить сотрудник и там он включаться не должен. Единственное, что я придумал, это unset'нуть офис с помощью foreach. Как думаете, правильно ли это? Вроде тут JSONResource должен быть один (судя по туторам, которым я смотрел) но я блин никак не могу понять, как мне без костыля сделать.

вот, что происходит в моем "костыльном" коде. У меня как бы office остается null, но блин, это 100% неправильно

{
    "status": true,
    "response": [
        {
            "id": 1,
            "code": "e4bK4A0UIE",
            "address": "Ленина, 10",
            "employees": [
                {
                    "id": 7,
                    "name": "Elyssa Grady",
                    "office": null
                },
                {
                    "id": 8,
                    "name": "Manuel Schimmel",
                    "office": null
                },
                {
                    "id": 10,
                    "name": "Thelma Vandervort",
                    "office": null
                }
            ],
            "created_at": "2021-04-11T12:50:56.000000Z"
        },
}


впринципе с костылем у меня всё работает правильно --> domain.ru/api/employees возвращает то, что нужно (ниже код прикрепил), однако я думаю это наотрез неправильный подход, что я вручную что-то unset'аю

api.php

Route::get('employees', function (Request $request) {
    return response()->json([
        "status" => true,
        "response" => new EmployeeCollection(Employee::all())
    ], 200);
});


возвращаемый ответ domain.ru/api/employees
{
    "status": true,
    "response": [
        {
            "id": 1,
            "name": "Schuyler Kilback",
            "office": {
                "id": 4,
                "code": "8ZJzJpdNe!",
                "address": "ySm7XUUIgpkWYfuHoaFG",
                "created_at": "2021-04-11T12:50:56.000000Z"
            }
        },
     ]
}
  • Вопрос задан
  • 714 просмотров
Решения вопроса 1
alexey-m-ukolov
@alexey-m-ukolov Куратор тега Laravel
The whenLoaded method may be used to conditionally load a relationship. In order to avoid unnecessarily loading relationships, this method accepts the name of the relationship instead of the relationship itself:

use App\Http\Resources\PostResource;

/**
 * Transform the resource into an array.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
public function toArray($request)
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'email' => $this->email,
        'posts' => PostResource::collection($this->whenLoaded('posts')),
        'created_at' => $this->created_at,
        'updated_at' => $this->updated_at,
    ];
}

In this example, if the relationship has not been loaded, the posts key will be removed from the resource response before it is sent to the client.

https://laravel.com/docs/8.x/eloquent-resources#co...

В доке речь про коллекцию, у вас же одна модель, но всё остальное применимо.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы