Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Допустим есть платежные методы данного юзера и только один из них является методом по умолчанию. Признака is_default у платежного метода нет. Зато у юзера есть поле в котором храниться id метода по умолчанию
class PaymentMethod extends Model
{
....
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
...
}
class User extends Authenticatable
{
...
public function payment_methods()
{
return $this->hasMany(AppPaymentMethod::class, $this->getForeignKey())->orderBy('created_at', 'desc');
}
public function default_payment_method()
{
return $this->hasOne(AppPaymentMethod::class, 'id', 'default_payment_method_id');
}
public function getDefautPaymentMethod()
{
$paymentMethod = $this->default_payment_method()->first();
return $paymentMethod;
}
...
}
Как для юзера взять в шаблоне его умолчательный метод ясно и работает
@if($user -> getDefautPaymentMethod()->type == PaymentMethod::PAYPAL_ACCOUNT)
<div><strong>Paypal: </strong> {{$user -> getDefautPaymentMethod()-> paypal_email}}</div>
@else
<div><strong>Card: </strong>{{$user -> getDefautPaymentMethod()-> card_brand}} **** **** **** {{$user -> getDefautPaymentMethod()-> card_last_four}}</div>
@endif
А теперь хотелось бы для каждого юзера в списке всех методов метод по умолчанию выделить. Как это красиво сделать?
Вот цикл
@foreach($user->payment_methods()->get() as $payment_method)
@if($payment_method ->type == PaymentMethod::PAYPAL_ACCOUNT)
<div><strong>Paypal: </strong> {{$payment_method -> paypal_email}}</div>
@else
<div><strong>Card: </strong>{{ $payment_method -> card_brand }} **** **** **** {{$payment_method -> card_last_four}}</div>
@endif
@endforeach
Причем подзапроса который бы выполнялся в каждой итерации цикла не хотелось бы как и DB::RAW. Думаю в PaymentMethod нужно метод добавить который будет использовать отношение с User и проверять существует ли объект по этому отношению. Или когда беру все платежные методы $user->payment_methods()->get() как то взять их with user по отношению через PaymentMethod.id = User.default_payment_method_id
Не в сети
Не в сети
Многие по многим не пойдет. Ведь один платеж может быть только одной картой. У юзера может быть много карт, но карта может принадлежать лишь одному юзеру. Даже если мы возьмум одну и туже карту и два раза зарегистируемся и ее введем, это будет разные PaymentMethod тк в платежном шлюзе разные.
Так, что структуру кажется я верно отразил.
if ($payment_method->id === $user->default_payment_method_id)
Логично тк юзер то известен для данной таблицы! Надо было так и сделать. Но я сделал так:
<h3>Payment methods</h3>
<table border="1">
<tr><th></th><th></th><th></th></tr>
@foreach($user->payment_methods()->withCount('defaultForUser')->get() as $payment_method)
<tr>
<td>
<div><strong>id:</strong> {{$payment_method->id }}</div>
<div><strong>gateway id:</strong> {{ $payment_method->braintree_id }}</div>
</td>
<td>
@if($payment_method ->type == PaymentMethod::PAYPAL_ACCOUNT)
<div><strong>Paypal: </strong> {{$payment_method -> paypal_email}}</div>
@else
<div><strong>Card: </strong>{{ $payment_method -> card_brand }} **** **** **** {{$payment_method -> card_last_four}}</div>
@endif
<td>
@if ($payment_method -> default_for_user_count)
<strong style = "color:green">Default</strong>
@endif
</td>
</td>
</tr>
@endforeach
</table>
Не в сети
$user->payment_methods()->withCount('defaultForUser')->get()
Кстати, а вот такие штуки в шаблонах надо ли прятать в метод модели в данном случае PaymentMethod ?
Что бы было типа $user->payment_methods()->getWirhDefaultForUser();
Не в сети
А на стаке мне вот что предложили:
@foreach ($user->payment-methods()->get() as $payment_method)
<div>
@if ($user->get_default_payment_method()->id === $payment_method->id)
<strong>Default Payment Method</strong>
@endif
{{ $payment_method }}
</div>
@endforeach
По сути тоже самое что ты.. Сравнивать прямо в цикле.
Не в сети
Кстати, а вот такие штуки в шаблонах надо ли прятать в метод модели в данном случае PaymentMethod ?
В шаблонах вообще запросов не должно быть. Нужно заранее подгружать все данные и работать с результатом в представлении.
Многие по многим не пойдет. Ведь один платеж может быть только одной картой.
Я говорю об отношении между User и PaymentType.
По сути тоже самое что ты.. Сравнивать прямо в цикле.
Это создаст дополнительно N запросов, мой код нет.
Не в сети
В шаблонах вообще запросов не должно быть. Нужно заранее подгружать все данные и работать с результатом в представлении.
Хорошо, а как верно эту eloquent конструкцию спрятать? В контроллер не хочу, нет смысла.. он должен быть тонкий да и вообще контроллеров много, а суть запроса одна. Почему бы не спрятать в модель?
Я говорю об отношении между User и PaymentType.
А оно не многое ко многим. Данный PaymentType не может принадлежать более чем одному юзеру
Это создаст дополнительно N запросов, мой код нет.
Да тк ты обращаешся просто к полю user
Не в сети
Главный сейчас вопрос
$user->payment_methods()->withCount('defaultForUser')->get()
И другие подобные конструкции в views верно ли было бы спрятать в методы модели? И что бы в views обращаться через $user и его отношения к данным методом моделей?
Не в сети
Почему бы не спрятать в модель?
Да, помести в модель. Контроллер передаст загруженные данные в представление.
Да тк ты обращаешся просто к полю user
А разве $user->default_payment_method_id вернет не тоже самое, что $user->get_default_payment_method()->id?
Не в сети
А разве $user->default_payment_method_id вернет не тоже самое, что $user->get_default_payment_method()->id?
не тоже самое $user->get_default_payment_method() вернет для юзера сам дефолтный пеймент метод, а то что ты указал вернет лишь строку с его id
Вот я думаю а как лучше поместить в модель... Чуть позже пришлю как сделал
Не в сети
Отладил таким образом
class User extends Authenticatable
{
....
public function payment_methods()
{
return $this->hasMany(AppPaymentMethod::class, $this->getForeignKey())->orderBy('created_at', 'desc');
}
public function getPaymentMethods()
{
return $this->payment_methods()->withCount('defaultForUser')->get();
}
....
}
class PaymentMethod extends Model
{
...
public function defaultForUser()
{
return $this->belongsTo(User::class, 'id', 'default_payment_method_id');
}
...
}
@foreach($user->getPaymentMethods() as $payment_method)
@endforeach
Конечно было бы наверное правильнее в PaymentMethod добавить метод который возвращает withCount('defaultForUser')->get(); и еще его вызывать в User через отношение... Но вроде и так норм..
А Scope в таких примерах никак не применимы?
Скажем для withCount('defaultForUser') и уже вызывать PaymentMethod с его использованием...
Изменено htclog81 (16.11.2017 14:52:30)
Не в сети
не тоже самое $user->get_default_payment_method() вернет для юзера сам дефолтный пеймент метод, а то что ты указал вернет лишь строку с его id
Но ты же делаешь $user->get_default_payment_method()->id а не $user->get_default_payment_method(). Т.е. просто так исполняешь кучу лишних запросов в БД. Установи Laravel Debugbar, чтобы наблюдать за запросами.
Не в сети
Но ты же делаешь $user->get_default_payment_method()->id а не $user->get_default_payment_method(). Т.е. просто так исполняешь кучу лишних запросов в БД. Установи Laravel Debugbar, чтобы наблюдать за запросами.
Я знаю понимаю. Я этот метод вроде бы и не использую в итоге? Посмотри, что я в итоге прислал... Debugbar скоро установлю. Я его удалил тк он мне портил ответы WebHook его js скрипты ответ сервера засоряли.
Не в сети
Включил я в итоге debug bar
Запрос получился вот таким:
select `payment_method`.*, (select count(*) from `users` where `payment_method`.`id` = `users`.`default_payment_method_id`) as `default_for_user_count` from `payment_method` where `payment_method`.`user_id` = '1' and `payment_method`.`user_id` is not null and `payment_method`.`deleted_at` is null order by `created_at` desc
Помойму вполне терпимо. Я и на голом php так писал. Это же в не цикле подзапросы. select count со связкой по ключу норм
Не в сети
Это при использовании $user->get_default_payment_method()->id?
Не в сети
Нет.
Это вот
class User extends Authenticatable
{
....
public function payment_methods()
{
return $this->hasMany(AppPaymentMethod::class, $this->getForeignKey())->orderBy('created_at', 'desc');
}
public function getPaymentMethods()
{
return $this->payment_methods()->withCount('defaultForUser')->get();
}
....
}
class PaymentMethod extends Model
{
...
public function defaultForUser()
{
return $this->belongsTo(User::class, 'id', 'default_payment_method_id');
}
...
}
@foreach($user->getPaymentMethods() as $payment_method)
@endforeach
Не в сети