Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Страницы 1
Добрый день.
Сегодня с утра после прочитанного https://laravel.ru/forum/viewtopic.php?pid=13583#p13583 задумался.
Я ведь как и многие, начинал учить ларавел по видосам Ларакаст. И Джефри там делает запросы прямо в контроллере. Получается это не правильно? как так то?
В связи с этим возникло пару вопросов:
1. У меня есть модель Product в которой и так порядка 15 методов (в основном связи и мутаторы). Если я буду делать как пишет Алексей, то у меня модель конкретно разжирнеет. Разве это нормально?
2) Как быть вот с этим:
/**
* Show the form for editing the specified resource.
*
* @param Product $product
* @return \Illuminate\Http\Response
*/
public function edit(Product $product)
{
return view('product.edit', [
'product' => $product->load('categories', 'variations.combinations', 'carriers', 'images'),
'oldCategories' => $product->categories->pluck('id')->toArray(),
'oldCarriers' => $product->carriers->pluck('id')->toArray(),
'categories' => Category::orderBy('parent_id', 'asc')->get(['id', 'name', 'parent_id']),
'carriers' => Carrier::orderBy('name', 'asc')->get(),
'manufacturers' => Manufacturer::orderBy('name', 'asc')->get(),
'attributes' => Attribute::with(['values' => function($q) {$q->orderBy('sort_order', 'asc');}])->orderBy('sort_order', 'asc')->get(),
'taxes' => Tax::orderBy('name', 'asc')->get(),
'languages' => $this->languages,
'variations' => $product->variations,
'images' => $product->images,
]);
}
Придется каждую модель через конструктор инъектить. Контроллер тогда тоже жирным станет. Мне эти моменты не понятны. Буду признателен если ктонибудь мне это объяснит.
Спасибо.
Не в сети
Т.к. ты сослался на мои слова, давай я начну. У тебя контроллер выглядит неплохо только потому, что запросы очень простые. В более крупном проекте ты сам поймешь, что запросы необходимо выносить. Увидишь полностью засранный контроллер, который невозможно прочитать и сам начнешь создавать skinny controllers.
Что, если вместо Сarrier::orderBy('name', 'asc')->get(), у тебя будет что-то такое:
$this->whereHas('publication', function ($q) {
$q->where('user_id', auth()->id());
})
->where(function ($q) {
$q->whereHas('comments', function ($q) {
$q->where('read', false)
->where('user_id', '<>', auth()->id());
})
->orWhere('read', false);
})
->count();
А это относительно простой запрос. Есть код с несколькими if/else, работой со связями в update методах, скоупами с параметрами и т.д.
Джефри так делает, потому что это простой способ показать новичку как работать с Laravel. По этой же причине в контроллерах работают с валидацией, с данными, curl, файлами, кто-то даже с представлениями работать умудряется. Это нарушает принцип единственной ответственности (single responsibility principle) и сам шаблон проектирования MVC.
В некоторых уроках учат кодить прямо в файлах маршрутов, но это не значит, что ты должен это делать в реальном приложении. Минус этого подхода к обучению в том, что большинство людей дальше просмотра кастов не учатся и делают проекты клиентам с помощью копипасты с использованием плохих и/или устаревших практик. До сих пор помню проект, в котором человек воротил код прямо в маршрутах. В итоге, клиент потерял время и дважды потратил деньги, потому что такое "приложение" поддерживать вообще нереально. Видел и проекты с контроллерами в несколько тысяч строк, на поддержку которых клиенты не могут найти разработчика, ибо с этим кодом соглашаются работать только копеечные индусы.
На счет контейнера. Ты можешь не внедрять зависимости через контейнер, а использовать фасады. На эту тему были споры, когда Отвелла закидали камнями за использование фасадов, после чего в коде новых примеров в документации он стал показывать уже использование IoC. Я внедряю через контейнер, хотя и с фасадами можно работать примерно также, они мокаются и т.д.
Давайте обсудим.
Изменено AlexeyMezenin (07.08.2017 11:07:24)
Не в сети
А давайте рассмотрим и обсудим как вариант хорошей практики репозиторий.
Вот например в данном пакете вся логика запросов лежит в нем https://github.com/bestmomo/laravel5-3- … positories
А его уже как зависимость вставлять в контроллер.
В случае ТС если ему скажем нужно заполнить меню которое на многих страницах одинаковые категории из БД, то лучше это сделать в ViewComposer. А в контроллере редактирования продукта выбирать только продукт и то что с ним связано и нужно для редактирования, скажем его атрибуты и картинки. И все это можно сделать одним вызовом метода репозитория типа $repo->getProductFullInfoForEdit(). Ну а ORM запрос к БД уже внутри класса репозитория.
PS. Я сам конечно только учусь
Не в сети
В двух словах повторю свое мнение, озвученное в соседней ветке. Используешь Eloquent - репозиторий является лишней абстракцией, пишешь сырые запросы или используешь Query Builder без моделей - используешь репозиторий.
Изменено AlexeyMezenin (07.08.2017 11:06:10)
Не в сети
- А это относительно простой запрос. Есть код с несколькими if/else, работой со связями в update методах, скоупами с параметрами и т.д.
С этим все понятно. А если запрос простой типо выбрать все и отсортировать, то его тоже в моделях оформлятьь методом типо PHPpublic function getAllWithOrderBy($field, $type = 'asc'){/*...*/};
или всетаки можно оставить запрос в контроллере как у меня в коде с Carrier-ом?
- Джефри так делает, потому что это простой способ показать новичку как работать с Laravel. По этой же причине в контроллерах работают с валидацией, с данными, curl, файлами, кто-то даже с представлениями работать умудряется. Это нарушает принцип единственной ответственности (single responsibility principle) и сам шаблон проектирования MVC. В некоторых уроках учат кодить прямо в файлах маршрутов, но это не значит, что ты должен это делать в реальном приложении. Минус этого подхода к обучению в том, что большинство людей дальше просмотра кастов не учатся и делают проекты клиентам с помощью копипасты с использованием плохих и/или устаревших практик. До сих пор помню проект, в котором человек воротил код прямо в маршрутах. В итоге, клиент потерял время и дважды потратил деньги, потому что такое «приложение» поддерживать вообще нереально. Видел и проекты с контроллерами в несколько тысяч строк, на поддержку которых клиенты не могут найти разработчика, ибо с этим кодом соглашаются работать только копеечные индусы.
Спасибо за разъяснение. теперь понятно почему так делают.
- На счет контейнера. Ты можешь не внедрять зависимости через контейнер, а использовать фасады. На эту тему были споры, когда Отвелла закидали камнями за использование фасадов, после чего в коде новых примеров в документации он стал показывать уже использование IoC. Я внедряю через контейнер, хотя и с фасадами можно работать примерно также, они мокаются и т.д.
Мне вот только одно непонятно. У меня в примере используется 5 моделей. если сделать так, то это будит нормально?
/**
* @var Product
*/
public $product;
/**
* @var Category
*/
public $category;
/**
* @var Manufacturer
*/
public $manufacturer;
/**
* @var Tax
*/
public $tax;
/**
* @var Carrier
*/
public $carrier;
/**
* BackendProductController constructor
*
* @param Product $product
* @param Category $category
* @param Manufacturer $manufacturer
* @param Tax $tax
* @param Carrier $carrier
*/
public function __construct(Product $product, Category $category, Manufacturer $manufacturer, Tax $tax, Carrier $carrier)
{
parent::__construct();
$this->product = $product;
$this->category = $category;
$this->manufacturer = $manufacturer;
$this->tax = $tax;
$this->carrier = $carrier;
}
Не в сети
А если запрос простой типо выбрать все и отсортировать, то его тоже в моделях оформлятьь методом
Да, потому что это тоже работа с данными. Плюс, этот метод можно будет использовать в нескольких контроллерах (DRY) и при внесении изменений в код ты его будешь менять только в одном месте.
Если сделать так, то это будит нормально?
Да, только непонятно зачем ты вызываешь parent::__construct()
Не в сети
Есть ещё такой интересный подход.
Не в сети
- Да, потому что это тоже работа с данными. Плюс, этот метод можно будет использовать в нескольких контроллерах (DRY) и при внесении изменений в код ты его будешь менять только в одном месте.
- Да, только непонятно зачем ты вызываешь parent::__construct()
У меня есть общие методы для всех контроллеров типо этих
/**
* Get configuration
*
* @param null $file
* @return mixed
*/
public function getSettings($file = null)
{
if(is_null($file))
{
return Config::all();
}
return Config::get($file);
}
/**
* Set value to config
*
* @param $file
* @param array $values
*/
public function setSettings($file, array $values = [])
{
Config::write($file, $values);
}
/**
* Determine current shop
*
* @param null $value
* @return \Illuminate\Database\Eloquent\Model|mixed|null|static
*/
public function getCurrentShop($value = null)
{
$host = str_replace('www.', '', request()->getHost());
$shop = Shop::where('domain', $host)->first();
if(is_null($value))
return $shop;
return $shop->{$value};
}
Которые находятся в BackendBaseController, а все остальные контроллеры наследуют его.
Не в сети
Страницы 1