#laravel #eloquent #eloquent-relationship #laravel-eloquent-resource
Вопрос:
У меня есть Красноречивая модель Laravel под названием EmailList
и модель под названием Subscriber
. Я определил следующие отношения hasMany в списке рассылки.
public function subscribers() {
return $this->hasMany(Subscriber::class);
}
Эти отношения прекрасно работают.
Теперь я хочу применить where()
условие к родителю и where()
условие к ребенку.
Например, у меня есть два EmailList
s, со свойством id
и свойством под названием listname
(«Список A» и «Список B»). Моя Subscriber
модель имеет четыре соответствующих свойства: id
, name
, email
и email_list_id
.
Проблема: Я хочу взять всех подписчиков из определенного списка, например «Список А», и отфильтровать подписчиков с $query
помощью (функция поиска с помощью Livewire).
Чтобы выполнить это, я придумал следующий код:
EmailList::where('listname', $listname)->first()
->subscribers()
->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
->paginate(50) //or get(), if you like
Этот код частично сработал, потому что подписчики действительно были отфильтрованы, но не список рассылки. Другими словами, я просто искал всех подписчиков, а не подписчиков в определенном списке.
После долгих поисков я понял , что, возможно, мне следует использовать a whereHas()
, но когда я попытался это сделать, он дал мне только списки рассылки, а не Подписчиков.
Было бы здорово, если бы кто-нибудь мог помочь мне отфильтровать это. Возможно, это мелочи для опытного разработчика,, но мне бы это очень помогло!
Обновление: Увидев ответ Эрикландхеера, я понял, что (конечно) У меня также есть идентификатор списка рассылки. Возможно, это немного упрощает задачу, так что вы можете использовать функцию find() вместо предложения where()->first (). (Я использую first (), потому что «имя списка» уникально, и мне нужен только один экземпляр. Это правильно?)
Комментарии:
1. попробуйте этот $поиск=$это->поиск; $данные= список рассылки::где(‘имя списка’, $имя списка)->>с(‘подписчики’)->>>Где(‘подписчики’,функция ($запрос)использовать($поиск){ $запрос->>>>где(‘электронная почта’, ‘НРАВИТСЯ’, ‘%’.$поиск.’%’); })->>>>>где(функция ($запрос)использовать($поиск){ $запрос->>>>>>где(«имя», «НРАВИТСЯ», «%».$поиск.’%’) ->>>>>>>Или где(«электронная почта», «НРАВИТСЯ», «%».$поиск.’%’); })->>>>>>>>разбиение на страницы(50);
2. Эй, Джон, спасибо! Не могли бы вы, возможно, изложить это в ответе? Я проверю это и дам вам знать!
Ответ №1:
В настоящее время ваш код возвращает только первое EmailList
. Вы сделали это намеренно, или вам нужен только первый EmailList
, у которого есть $listname
?
Вот решение, использующее быструю загрузку с ограничениями, которое переопределяет subscribers
связь с обратным вызовом. В результате должны быть все EmailLists
$listname
подписчики и соответствующие подписчики с поиском.
EmailList::where('listname', $listname)
->with('subscribers', function($query) {
return $query->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
})->get();
Что касается обновления вопроса
Действительно, использование имени списка-это нормально. Если он уникален, никаких проблем. Вы можете использовать find()
с идентификатором to, что предпочтительнее, если вы подумываете об изменении имени EmailList
на более позднем этапе.
Возможно, более элегантным / читаемым решением было бы:
$emailList = EmailList::firstWhere('listname', $listname);
$emailList->subscribers = $emailList->subscribers()
->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
->get();
Вы можете преобразовать поиск в модель / услугу, если используете его в большем количестве мест:
// EmailList model
public function subscribers()
{
return $this->hasMany(Subscriber::class);
}
public function searchSubscribers(string $search): Collection
{
return $this->subscribers()
->where('name', 'LIKE', '%'.$this->search.'%')
->orWhere('email', 'LIKE', '%'.$this->search.'%')
->get();
}
Окончательный код
$emailList = EmailList::firstWhere('listname', $listname);
$emailList->subscribers = $emailList->searchSubscribers($this->search);
Комментарии:
1. Большое спасибо, Эрик, я проверю и дам тебе знать!
2. Я обновил свой первоначальный ответ, на мой взгляд, с более чистым подходом. Я не проверял это, но, по-моему, это довольно просто. Рассмотрите возможность рефакторинга
search()
функции в отдельный класс (например, UserSearchService), если функция также используется в других классах.3. Эй, Эрик, большое спасибо за твой ответ. Я выбрал более чистое решение👍