Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Но все же наверное есть классы которые вообще дурной тон класть в общую папку с другими, например Нотификации или Провайдеры там же сама Ларавель папки создает...
В тоже время по мне так лучше на папки все побить. Но в то же время в конце класса не дописывать Service Helper Interface итд
А имеет ли смысл держать контракты, трейты, сервисы, интерфейсы каждые в своей папке? Или только часть этих классов заслуживает отдельной папки? должны ли все они так или иначе лежат в папке Models или типа того?
>Переменные $articlesWithAuthor
Это сначала articles тк сначала их берем в запросе. Множественное число тк коллекция. Для каждого артикла один автор и потому он единственный. Те все исходит из здравого смысла и содержимого переменной.
"Контракт (интерфейс): прилагательное или существительное Authenticatable"
То есть СhangePasswordContract ChangePasswordService те включающие контракт сервис названия плохие...
Сервис и репозиторий как называть я бы тоже внес в таблицу.
А сокращение Pass вместо Password Trans вместо Transaction плохо?
А если название модели PaymentMethod то во множественном метод ты бы назвал getPaymentMethods или getPaymentsMethods ?
Хорошо. А методы внутри модели которые не являются отношениями?
Например
public function paymentWithMethod()
{
return $this->payments()->with('payment_method', 'subscription.plan')->get();
}
public function paymentMethodWithIsDefault()
{
return $this->payment_methods()->withCount('defaultForUser')->get();
}
Как лучше назвать в плане числа? Если первый возращает платежи вместе с картами. А второй карты с признаком какая умолчательная..
При этом названия классов в единственном - Subscription Payment PaymentMethod, а не Subscription, Payments, PaymentMethods??Почему? Там же hasMany.
Тут я не про отношения уже спрашиваю, а про сами классы как называть
Или ты не про мою тему, а про тему именно с запросом по ошибке?
Специально не создавал... Может форма два раза отправилась... Конечно надо одну оставить тему.
нужно именовать методы method_name или methodNamemethodName
И для отношений типа
public function paymentMethods()
{
return $this->hasMany(AppPaymentMethod::class, $this->getForeignKey())->orderBy('created_at', 'desc');
}
Так?
в каком случае мы берем множественное число, а в каком единственноеЕдинственное число для hasOne и belongsTo, множественное для всех остальных.
При этом названия классов в единственном - Subscription Payment PaymentMethod, а не Subscription, Payments, PaymentMethods??
А методы не связанные с отношениями? Смотря что они возвращают? От этого зависит единственное или множественное число? Если возвращают коллекцию то множественное? Если один объект то единственное?
Первый вопрос
Допустим есть класс Eloquent модели. В нем есть отношения и свои какие то еще методы:
А в каком регистре или как правильно назвать, нужно именовать методы method_name или methodName
Дело в том что изначально и в том числе в пакетах вроде бы отношения пишут как method_name, в тоже время вроде бы хороший тон свои функции писать как methodName
Второй вопрос:
А в каком случае мы берем множественное число, а в каком единственное:
Например, вроде бы имя модели единственное число правильно писать... А имя отношения вроде бы множественное..
В общем что бы тут пофиксить и переименовать в указанном выше смысле
<?php
namespace App\Classes\Models;
use Illuminate\Notifications\Notifiable;
//use App\Notifications\CustomResetPassword;
use Illuminate\Foundation\Auth\User as Authenticatable;
use \Plunk\Mediable;
use Laravel\Cashier\Billable;
use \Plank\Mediable\Mediable as PlunkMediable;
use Braintree\PaymentMethod as BraintreePaymentMethod;
use Braintree\PayPalAccount as BraintreePayPalAccount;
use Braintree\Customer as BraintreeCustomer;
use Braintree\Transaction as BraintreeTransaction;
use Braintree\Subscription as BraintreeSubscription;
use Illuminate\Support\Arr;
use App\Classes\Models\PaymentMethod as AppPaymentMethod;
class User extends Authenticatable
{
use Notifiable;
use Billable;
use PlunkMediable;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function subscriptions()
{
return $this->hasMany(Subscription::class, $this->getForeignKey())->orderBy('created_at', 'desc');
}
public function newSubscription($subscription, $plan)
{
return new SubscriptionBuilder($this, $subscription, $plan);
}
public function payments()
{
return $this->hasMany(Payment::class, $this->getForeignKey())->orderBy('created_at', 'desc');
}
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 paymentMethodWithIsDefault()
{
return $this->payment_methods()->withCount('defaultForUser')->get();
}
public function getDefautPaymentMethod()
{
$paymentMethod = $this->default_payment_method()->first();
return $paymentMethod;
}
public function paymentWithMethod()
{
return $this->payments()->with('payment_method', 'subscription.plan')->get();
}
Готово так
<table border="1">
@foreach($user -> paymentWithMethod() as $payment)
<tr>
<td>
<div><strong>id:</strong> {{$payment->id }}</div>
<div><strong>gateway id:</strong> {{ $payment->gateway_id }}</div>
</td>
<td>
{{$payment->type}}
</td>
<td>
{{$payment->amount}}$
</td>
<td>
{{$payment->created_at}}
</td>
<td>
@if($payment -> payment_method -> type == PaymentMethod::PAYPAL_ACCOUNT)
<div><strong>Paypal: </strong> {{ $payment -> payment_method -> paypal_email }}</div>
@else
<div><strong>Card: </strong>{{ $payment -> payment_method -> card_brand }} **** **** **** {{ $payment -> payment_method -> card_last_four }}</div>
@endif
<div><strong>id:</strong> {{ $payment -> payment_method -> id }}</div>
<div><strong>gateway id:</strong>{{ $payment -> payment_method -> braintree_id }}</div>
</td>
<td>
<div><strong>id:</strong> {{$payment->subscription->id }}</div>
<div><strong>gateway id:</strong> {{ $payment->subscription->braintree_id }}</div>
<div><strong>plan:</strong> {{ $payment->subscription->plan->name }}</div>
<div><strong>period:</strong> {{ $payment->period_start->format('d.m.Y')}} - {{ $payment->period_end->format('d.m.Y') }}</div>
</td>
<td>
@if (!empty($payment -> void_at))
<div>void {{$payment -> void_at}}</div>
@else
@if (!empty($payment->refund_at))
<div>refunded {{$payment->refund_at}} </div>
@endif
@if (!$payment->refunded_transaction_id && !$payment->refund_at)
<div><a href="{{ route('admin.payment_cancel', [$user->id, $payment->id]) }}" onclick="return confirm('Are you sure?')">Refund payment</a></div>
@endif
@if ($payment->refunded_transaction_id)
<div>refund {{$payment->refunded_transaction_id}}</div>
@endif
<div><a href="{{ route('admin.payment_settle', [$user->id, $payment->id]) }}" onclick="return confirm('Are you sure?')">Settle payment</a> <small>(Only in testing enviroment)</small></div>
@endif
</td>
</tr>
@endforeach
</table>
class User extends Authenticatable
{
public function payments()
{
return $this->hasMany(Payment::class, $this->getForeignKey())->orderBy('created_at', 'desc');
}
public function paymentWithMethod()
{
return $this->payments()->with('payment_method', 'subscription.plan')->get();
}
Даже два отношения понадобилось. В целом все понятно и применена нетерпеливая загрузка
Вот моя тема
https://laravel.ru/forum/viewtopic.php?pid=14907 тут есть ответы и вообще несколько сообщений. Эта ссылка из уведомления по мейлу.
https://laravel.ru/forum/viewtopic.php?id=3045 А тут только мой вопрос и нет почему то ответов. Эта ссылка в самом форуме. И еще и 0 ответов написано там в списке тем. Но это же неверно!
Ну и используй нетерпеливую загрузку.
Да, вижу как раз про with речь и идет...
Видимо имеет смысл добавить в модель метод который вернет то что нужно используя with ну и в шаблоне дергать его. А в контроллере передавать только $user
В целом я верно понимаю?
Я понимаю что можно подгрузить в контролере. Но а если а хочу что бы в модель передавать только $user и далее обращаться через его отношения, но без кучи этих подзапросов? В какую сторону смотреть что то типа With ? А хорошая ли это практика в данном случае?
Вывожу историю платажей для пользователя. У пользователя несколько платежей. Отношение один ко многим. У платежа один платежный метод отношение один к одному
Модели
class User extends Authenticatable
{
public function payments()
{
return $this->hasMany(Payment::class, $this->getForeignKey())->orderBy('created_at', 'desc');
}
}
class Payment extends Model
{
public function payment_method()
{
return $this->belongsTo(PaymentMethod::class, 'payment_method_id', 'id');
}
И в шаблоне
<table border="1">
<tr>
<th>
</th>
<th>
summ
</th>
<th>
date
</th>
<th>
payment method
</th>
<th>
subscription
</th>
<th></th>
</tr>
@foreach($user -> payments()->get() as $payment)
<tr>
<td>
{{$payment->type}}
</td>
<td>
{{$payment->amount}}$
</td>
<td>
{{$payment->created_at}}
</td>
<td>
@if($payment -> payment_method()->first()->type == PaymentMethod::PAYPAL_ACCOUNT)
<div><strong>Paypal: </strong> {{ $payment -> payment_method() -> first() -> paypal_email }}</div>
@else
<div><strong>Card: </strong>{{ $payment -> payment_method() -> first() -> card_brand }} **** **** **** {{ $payment -> payment_method() -> first() -> card_last_four }}</div>
@endif
</td>
<td>
<div><strong>plan:</strong> {{ $payment->subscription->plan->name }}</div>
<div><strong>period:</strong> {{ $payment->period_start->format('d.m.Y')}} - {{ $payment->period_end->format('d.m.Y') }}</div>
</td>
<td>
@if (!empty($payment -> void_at))
<div>void {{ $payment -> void_at }}</div>
@elseif (!empty($payment->refund_at))
<div>refunded {{ $payment->refund_at }} </div>
@elseif(!empty($payment->refunded_transaction_id ))
<div>refund</div>
@endif
</td>
</tr>
@endforeach
</table>
Все это порождает множество запросов типа
select * from `payment_method` where `payment_method`.`id` = '3' and `payment_method`.`deleted_at` is null limit 1
select * from `payment_method` where `payment_method`.`id` = '3' and `payment_method`.`deleted_at` is null limit 1
Как это зарефакторить и переместить в модель, что бы не было множество запросов?
Нет.
Это вот
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
Включил я в итоге 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 а не $user->get_default_payment_method(). Т.е. просто так исполняешь кучу лишних запросов в БД. Установи Laravel Debugbar, чтобы наблюдать за запросами.
Я знаю понимаю. Я этот метод вроде бы и не использую в итоге? Посмотри, что я в итоге прислал... Debugbar скоро установлю. Я его удалил тк он мне портил ответы WebHook его js скрипты ответ сервера засоряли.
Отладил таким образом
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 с его использованием...
А разве $user->default_payment_method_id вернет не тоже самое, что $user->get_default_payment_method()->id?
не тоже самое $user->get_default_payment_method() вернет для юзера сам дефолтный пеймент метод, а то что ты указал вернет лишь строку с его id
Вот я думаю а как лучше поместить в модель... Чуть позже пришлю как сделал
А тебе точно нужна такая структура массива? Зачем?
Главный сейчас вопрос
$user->payment_methods()->withCount('defaultForUser')->get()
И другие подобные конструкции в views верно ли было бы спрятать в методы модели? И что бы в views обращаться через $user и его отношения к данным методом моделей?
В шаблонах вообще запросов не должно быть. Нужно заранее подгружать все данные и работать с результатом в представлении.
Хорошо, а как верно эту eloquent конструкцию спрятать? В контроллер не хочу, нет смысла.. он должен быть тонкий да и вообще контроллеров много, а суть запроса одна. Почему бы не спрятать в модель?
Я говорю об отношении между User и PaymentType.
А оно не многое ко многим. Данный PaymentType не может принадлежать более чем одному юзеру
Это создаст дополнительно N запросов, мой код нет.
Да тк ты обращаешся просто к полю user