У меня есть приложение laravel, которое позволяет пользователям публиковать сообщения. Каждый пост имеет цену (хранится в виде целого числа) и принадлежит университету, который, в свою очередь, принадлежит стране, в которой есть валюта.
Каждый раз, когда я получаю сообщения, я хочу вернуть и валюту. Я мог бы сделать with('university.country'), но это вернет все детали как по университету, так и по стране.
Я мог бы добавить getCurrencyAttribute и определить там логику, но мутаторы, похоже, не для этого, тем более, что если я получу все сообщения, каждое сообщение будет запускать два собственных запроса, просто чтобы получить валюту. Это 3 запроса для получения одного сообщения, что быстро сказывается при возврате более 10 сообщений.
public function getCurrencyAttribute() {
return $this->university->country->currency;
}
public function getPriceAttribute($value) {
return "{$this->currency}{$value}";
}
^ пример выше: нет необходимости в appends, потому что price автоматически перезаписывается. Это проблема, как видно на DebugBar (в модели Post вызываются два новых запроса, которые, хотя и ожидались, становятся неэффективными при получении большого количества сообщений):

Как лучше всего каждый раз получать одно связанное поле?
Запрос Eloquent изначально довольно прост: Post::get(). Смотрите полный код на GitHub :)! В настоящее время используется метод with для получения валюты, но он кажется неэффективным.
Вы можете использовать именно аксессоры, они предназначены для получения значения настраиваемого атрибута из модели.






Вы можете ограничить количество столбцов активной загрузки:
Post::with('webometricUniversity:uni-id,country_id',
'webometricUniversity.country:id,currency')->get();
Если он вам всегда нужен, добавьте это в свою модель Post:
protected $appends = ['currency'];
protected $with = ['webometricUniversity:uni-id,country_id',
'webometricUniversity.country:id,currency'];
public function getCurrencyAttribute() {
return $this->webometricUniversity->country->currency;
}
Тогда вы можете просто использовать Post::get() и $post->currency.
Я мог бы - но в идеале мне всегда нужна валюта при получении цены, поэтому я хотел бы настроить ее в модели, чтобы она всегда вытягивалась.
Я расширил свой ответ.
Выглядит хорошо, и хотя я еще не пробовал, похоже, он отлично работает! Единственное, что это просто выглядит для меня в том смысле, что я ожидал, что laravel уже будет какой-то реализацией или помощником, который занимается моей проблемой - это просто кажется обычным случаем, особенно для супер-нормализованных баз данных
Как $withнет «реализация или помощник, решающий мою проблему»?
Да, я думаю, вы правы: P Просто любопытно, если я установлю $with в модели, как вы показали выше, а затем снова вызову with('webometricUniversity') в контроллере, чтобы получить все сведения об университете, будет ли таблица удаляться дважды или laravel объединит withs ? Как вы думаете, это вообще правильный подход к валюте и ценообразованию в db: P?
Они объединяются, и with() имеет приоритет над $with.
Если вам нужна валюта всегда, возможно, денормализация стоит того.
Хорошо, код определенно работает, но я хотел бы получить его плоскую, а не вложенную, иначе говоря, чтобы поле валюты было только полем цены, а не вложено в webometricUniversity.country. Как я это сделал? Мне буквально просто нужно поле валюты ...
Вы используете аксессуар: getCurrencyAttribute: return $this->webometricUniversity->country->currency;
Да, это определенно работает. Я видел в нескольких статьях, как я уже упоминал в вопросе, что использование мутаторов / аксессуаров для этого не является хорошей идеей и не для того, для чего они предназначены ... но если это работает, то работает;)! Если вы обновите свой ответ, также включите protected $appends = [ 'currency' ];, чтобы другие могли видеть, как всегда прикреплять атрибут;)
Я обновил свой ответ. Я не вижу причин, по которым это было бы плохой идеей.
Просто на что-то наткнулся. При вызове списка сообщений каждое сообщение дополнительно выполняет запрос, чтобы получить университет, затем страну, всего 2 новых (нежелательных) запроса на сообщение вместо 1 запроса, чтобы получить все сообщения и валюту ... Есть мысли?
Вы используете ускоренную загрузку?
Нет, мне он нужен как атрибут, так как он переопределяет значение цены по умолчанию ... Жадная загрузка вернет меня к исходной точке. Могу ли я загрузить атрибут?
Можете ли вы добавить в свой вопрос код, который вы используете?
Просто сделал :) Также я обновил весь код на GitHub, что может дать немного больше информации :)
Где вы получаете доступ к currency и / или price?
Вызов Post::get() в контроллере сообщений в простейшем смысле. В модели уже есть поле цены, поэтому, когда я получаю атрибут цены, он просто перезаписывает значение новым, как в вопросе. На GitHub он немного расширен, но вы заметите, что мне не нужно специально называть атрибут цены: github.com/mwargan/JustBookr/blob/master/app/Http/Controller s /…
Post::get() выполняет запросы для university и country?
Ну, получая сообщения, он автоматически вызывает getPriceAttribute, который затем, в свою очередь, запрашивает university, а затем country для каждого полученного сообщения ... Итак, насколько я вижу, и панель отладки сообщает мне, да, он выполняет два других запрашивает один раз для каждого возвращенного сообщения.
Я не могу воспроизвести это.
Странно ... что тут могло помочь? Добавляете скриншоты запросов отладочных панелей?
Позвольте нам продолжить обсуждение в чате.
Вы можете показать свой точный запрос?