Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 07.08.2017 08:42:18

Best practices

Добрый день.
Сегодня с утра после прочитанного https://laravel.ru/forum/viewtopic.php?pid=13583#p13583 задумался.
Я ведь как и многие, начинал учить ларавел по видосам Ларакаст. И Джефри там делает запросы прямо в контроллере. Получается это не правильно? как так то?
В связи с этим возникло пару вопросов:
1. У меня есть модель Product в которой и так порядка 15 методов (в основном связи и мутаторы). Если я буду делать как пишет Алексей, то у меня модель конкретно разжирнеет. Разве это нормально?
2) Как быть вот с этим:

PHP
    /**
     * 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,
        ]);
    }

Придется каждую модель через конструктор инъектить. Контроллер тогда тоже жирным станет. Мне эти моменты не понятны. Буду признателен если ктонибудь мне это объяснит.
Спасибо.

Не в сети

#2 07.08.2017 09:11:29

Re: Best practices

Т.к. ты сослался на мои слова, давай я начну. У тебя контроллер выглядит неплохо только потому, что запросы очень простые. В более крупном проекте ты сам поймешь, что запросы необходимо выносить. Увидишь полностью засранный контроллер, который невозможно прочитать и сам начнешь создавать 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)

Не в сети

#3 07.08.2017 10:34:50

htclog81
Откуда: Москва
Сообщений: 192
Сайт

Re: Best practices

А давайте рассмотрим и обсудим как вариант хорошей практики репозиторий.

Вот например в данном пакете вся логика запросов лежит в нем https://github.com/bestmomo/laravel5-3- … positories

А его уже как зависимость вставлять в контроллер.

В случае ТС если ему скажем нужно заполнить меню которое на многих страницах одинаковые категории из БД, то лучше это сделать в ViewComposer. А в контроллере редактирования продукта выбирать только продукт и то что с ним связано и нужно для редактирования, скажем его атрибуты и картинки. И все это можно сделать одним вызовом метода репозитория типа $repo->getProductFullInfoForEdit(). Ну а ORM запрос к БД уже внутри класса репозитория.

PS. Я сам конечно только учусь

Не в сети

#4 07.08.2017 10:41:16

Re: Best practices

В двух словах повторю свое мнение, озвученное в соседней ветке. Используешь Eloquent - репозиторий является лишней абстракцией, пишешь сырые запросы или используешь Query Builder без моделей - используешь репозиторий.

Изменено AlexeyMezenin (07.08.2017 11:06:10)

Не в сети

#5 07.08.2017 13:06:09

Re: Best practices

  1. А это относительно простой запрос. Есть код с несколькими if/else, работой со связями в update методах, скоупами с параметрами и т.д.

С этим все понятно. А если запрос простой типо выбрать все и отсортировать, то его тоже в моделях оформлятьь методом типо PHPpublic function getAllWithOrderBy($field$type 'asc'){/*...*/}; или всетаки можно оставить запрос в контроллере как у меня в коде с Carrier-ом?

  1. Джефри так делает, потому что это простой способ показать новичку как работать с Laravel. По этой же причине в контроллерах работают с валидацией, с данными, curl, файлами, кто-то даже с представлениями работать умудряется. Это нарушает принцип единственной ответственности (single responsibility principle) и сам шаблон проектирования MVC. В некоторых уроках учат кодить прямо в файлах маршрутов, но это не значит, что ты должен это делать в реальном приложении. Минус этого подхода к обучению в том, что большинство людей дальше просмотра кастов не учатся и делают проекты клиентам с помощью копипасты с использованием плохих и/или устаревших практик. До сих пор помню проект, в котором человек воротил код прямо в маршрутах. В итоге, клиент потерял время и дважды потратил деньги, потому что такое «приложение» поддерживать вообще нереально. Видел и проекты с контроллерами в несколько тысяч строк, на поддержку которых клиенты не могут найти разработчика, ибо с этим кодом соглашаются работать только копеечные индусы.

Спасибо за разъяснение. теперь понятно почему так делают.

  1. На счет контейнера. Ты можешь не внедрять зависимости через контейнер, а использовать фасады. На эту тему были споры, когда Отвелла закидали камнями за использование фасадов, после чего в коде новых примеров в документации он стал показывать уже использование IoC. Я внедряю через контейнер, хотя и с фасадами можно работать примерно также, они мокаются и т.д.

Мне вот только одно непонятно. У меня в примере используется 5 моделей. если сделать так, то это будит нормально?

PHP
    /**
     * @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 $productCategory $categoryManufacturer $manufacturerTax $taxCarrier $carrier)
    {
        
parent::__construct();

        
$this->product $product;
        
$this->category $category;
        
$this->manufacturer $manufacturer;
        
$this->tax $tax;
        
$this->carrier $carrier;
    }

Не в сети

#6 07.08.2017 17:21:21

Re: Best practices

А если запрос простой типо выбрать все и отсортировать, то его тоже в моделях оформлятьь методом

Да, потому что это тоже работа с данными. Плюс, этот метод можно будет использовать в нескольких контроллерах (DRY) и при внесении изменений в код ты его будешь менять только в одном месте.

Если сделать так, то это будит нормально?

Да, только непонятно зачем ты вызываешь parent::__construct()

Не в сети

#7 07.08.2017 17:42:01

Re: Best practices

Есть ещё такой интересный подход.

Не в сети

#8 08.08.2017 09:05:39

Re: Best practices

  1. Да, потому что это тоже работа с данными. Плюс, этот метод можно будет использовать в нескольких контроллерах (DRY) и при внесении изменений в код ты его будешь менять только в одном месте.

Теперь все понятно. Спасибо!

  1. Да, только непонятно зачем ты вызываешь parent::__construct()

У меня есть общие методы для всех контроллеров типо этих

PHP
    /**
     * 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, а все остальные контроллеры наследуют его.

Не в сети

Подвал раздела