Laravel: Инъекция зависимости от фасадов?

То, что я делал ранее, это вводил только МОИ МОДЕЛИ, используя конструктор, и использовал Фасады для предоставленных классов Laravel, т.е. Session, Auth, Validator и т. д., например. Будет ли хорошей идеей, если я внедряю каждый класс (мой или Laravel) через конструкцию и использую его $this->.. синтаксис или я должен вводить свои собственные классы с помощью конструктора и использовать фасады для всего, что предусмотрено Laravel?

Чтобы быть более конкретным, вот как обычно выглядят мои контроллеры:

class MyController extends BaseController 
{
    public function __construct( User $user, Bookmark $bookmark ) {
        $this->user = $user;
        $this->bookmark = $bookmark
    }

    public function foobar ( ) {
        $user_id = Input::get('bar');
        ...
        Session::get('someInfo');
        ...
        return Redirect::to('/');
    }
    ...
}

Должен ли я структурировать свои методы, такие как контроллер, как следует, вместо этого?

class MyController extends BaseController 
{
    public function __construct( User $user, Bookmark $bookmark, Input $input, Session $session, Redirect $redirect ) {
        $this->user = $user;
        $this->bookmark = $bookmark
        $this->input = $input;
        $this->session = $session;
        $this->redirect = $redirect;
    }

    public function foobar ( ) {
        $user_id = $this->input->get('bar');
        ...
        $this->session->get('someInfo');
        ...
        return $this->redirect->to('/');
    }
    ...
}

4 ответа

Laravel теперь поддерживает те же функциональные возможности внедрения для методов классов (не только конструкторов), которые связаны с маршрутом, таких как контроллеры и промежуточное программное обеспечение.

Вы можете предотвратить ненужные внедрения, внедрив только те методы, у которых зависимость уникальна, возможно, оставив более общие зависимости в конструкторе:

class MyController extends BaseController 
{
    public function __construct( Input $input, Session $session, Redirect $redirect ) {
        $this->input = $input;
        $this->session = $session;
        $this->redirect = $redirect;
    }

    public function foobar ( User $user, Bookmark $bookmark ) {
        $user_id = $this->input->get('bar');
        ...
        $this->session->get('someInfo');
        ...
        return $this->redirect->to('/');
    }
    ...
}

Что касается того, следует ли вам делать это таким образом, то вам решать - заставить все зависимости появляться в определениях методов мне кажется чище и проще для модульного тестирования.

Изящно и полезно вводить определенные классы, такие как Запрос. По моему мнению, они должны быть указаны в методах контроллера там, где они необходимы, поскольку они затем логически связаны с реализацией метода. Круто пока.

Я нахожу два фасада проблематичными - App и Log. Ни логически не связаны с контроллером или его действиями. App и Log не являются входными данными ни в каком контексте. Так как App и Log являются служебными классами, они также имеют отношение к сервисам и репозиториям, и становится совсем неприятно, если вы напишите их в контроллерах, а затем передадите их в качестве параметров конструктора или метода в ваши классы поддержки.

Дополнительной проблемой является то, что фасад приложения не реализует интерфейс Illuminate\Contracts\Auth\Guard, который он проксирует, поэтому моя IDE загорается с предупреждениями, поскольку статический анализ невозможен.

Поэтому для согласованности и общего разделения интересов я бы, таким образом, создавал экземпляры App и Log в конструкторе или методе, в зависимости от того, насколько широко они используются в классе. Чтобы сделать мою среду IDE счастливой, я создал следующий класс, чтобы дать мне правильно напечатанный экземпляр везде, где он мне нужен:

<?php namespace App\Components;

use Illuminate\Contracts\Auth\Guard;
use Psr\Log\LoggerInterface;

/**
 * Get the underlying object instances of facades from the container.
 */
class AppGlobal
{
    /**
     * Returns the global logger instance.
     *
     * @return LoggerInterface
     */
    public static function log()
    {
        return app('log');
    }

    /**
     * Returns the global auth instance, which internally proxies a guard.
     *
     * @return Guard
     */
    public static function auth()
    {
        return app('auth');
    }

}

Если вам нужны свойства объекта - вставьте его как инъекцию (например, Input, Session...), в противном случае, если вы не сохраняете какие-либо данные в объекте и довольно довольны использованием класса, чем идти с фасадами (например, Log::..., Redirect::...).

Laravel заменил многие его фасады, например, помощниками

use Auth;

а также

Auth::user()

сейчас просто

auth()->user()

это делает вещь проще и аккуратнее (также предотвращает ошибки)

Я бы посоветовал использовать помощников, где это возможно, и, если помощников не существует, используйте фасад, потому что имитировать легче, чем внедренный экземпляр.

Другие вопросы по тегам