#php #laravel #api #eloquent #pivot-table
#php #laravel #API #eloquent #сводная таблица
Вопрос:
Laravel 5.7. У меня есть 2 модели Eloquent: Owner, Cat.
Модель владельца:
public function cats()
{
return $this->belongsToMany('AppCat')->withPivot('borrowed');
}
Модель Cat:
public function owners()
{
return $this->belongsToMany('AppOwner')->withPivot('borrowed');
}
cat_owner
Сводная таблица содержит эти поля:
id | cat_id | owner_id | borrowed
---------------------------------
1 | 3 | 2 | 1
Я хочу, чтобы мой API возвращал список всех cats, и если авторизованный пользователь позаимствовал этот cat, я хочу, чтобы для borrowed
поля было установлено значение true. Это то, что у меня есть на данный момент:
Контроллер:
public function index()
{
return CatResource::collection(Cat::all());
}
CatResource:
public function toArray()
{
$data = ['id' => $this->id, 'borrowed' => false];
$owner = auth()->user();
$ownerCat = $owner->cats()->where('cat_id', $this->id)->first();
if ($ownerCat) {
$data['borrowed'] = $ownerCat->pivot->borrowed == 1 ? true : false;
}
return $data;
}
Это работает, но кажется расточительным запрашивать $owner
для каждого cat, например, если в базе данных 5000 cats. Есть ли более эффективный способ сделать это? Я могу придумать 2 возможных способа:
-
Передать
$owner
вCatResource
(требуется переопределение существующего ресурса коллекции). -
Сначала получите эту информацию в контроллере, прежде чем передавать в
CatResource
.
Я предпочитаю второй способ, но не вижу, как это сделать.
Комментарии:
1. Если для cat и зарегистрированного владельца вообще нет сводной записи, результат не должен содержать
borrowed
поле?
Ответ №1:
Попробуйте условную связь.
public function toArray($request)
{
return [
'id' => $this->id,
'borrowed' => false,
'borrowed' => $this->whenPivotLoaded('cat_owner', function () {
return $this->owner_id === auth()->id() amp;amp; $this->pivot->borrowed == 1 ? true : false;
})
];
}
затем вызовите return CatResource::collection(Cat::with('owners')->get());
Комментарии:
1. Там нет логики сравнивать владельца cat с зарегистрированным владельцем.
2. Спасибо за настойчивость. К сожалению,
borrowed
ключ не доставляется. Я предполагаю, чтоwhenPivotLoading
возвращаетсяfalse
. Я используюwith('owners')
, поэтому я не уверен, что здесь происходит не так.3. @GluePear вы решили эту проблему? Я борюсь с точно такой же проблемой.
Ответ №2:
Вы правы, это создает большую дополнительную нагрузку. Я думаю, вы сталкиваетесь с ограничением, заключающимся в том, что вы не можете знать, какая форма записи cat_owner вам нужна, пока не узнаете обе записи, которые вы используете, из таблицы cat и owner.
Для всех, кто все еще заинтересован, моим решением было бы создать ресурс, который выдает вам только значения pivot
Поскольку следующее возвращает коллекцию, вы не можете перейти к сводной таблице по ней:
/*
* returns a collection
*/
$data['borrowed'] = $this->owners
/*
* So this doesNOT work. Since you can’t get the pivot
* data on a collection, only on a single record
*/
$data['borrowed'] = $this->owners->pivot
Вы должны получить коллекцию, а затем вы сможете прочитать сводные данные в Ресурсе записи владельца. Если этот ресурс предназначен только для сводных данных, я бы назвал его чем-то вроде атрибутов.
создайте новый ресурс для атрибутов, что-то вроде:
class CatOwnerAttributeResource extends JsonResource
{
public function toArray($request)
{
return [
'borrowed' => $this->pivot->borrowed,
];
}
}
Затем получите коллекцию следующим образом:
$data = ['id' => $this->id, 'borrowed' => false];
/*
* Get the collection of attributes and grab the first (and only) record.
* NOTE: the filtering is done in the collection, not in the DBM. If there
* is a possibility that the collection of owners who own this cat gets really
* big this is not the way to go!
*/
if ($attributes =
CatOwnerAttributeResource::collection(
$this->owner
->where(‘id’ = $auth->user()->id)
->first()
) {
$data[‘borrowed’] = $attributes->borrowed == 1 ? true : false;
}
return $data;
Не удалось запустить этот код, поэтому, пожалуйста, укажите на ошибки, если вы попробуете это, и это даст вам какие-либо, я исправлю.