[Laravel] サービスコンテナ、DIを正しく利用する

ITLaravel, PHP

サービスコンテナ、DI は Laravel の特徴の一つですが、そこをしっかり把握せずに自分は下記のように書いていました。

こうしたり

todoRepository = new TodoRepository();
    }

こうですね。。

/*
* Todo 一覧を表示する
*/
public function index()
{
  $tr = new TodoRepository();
  $todos = $tr->getAll();

  return view('todo.index', compact('todos'));
}

TodoRepository は自分が作成して、サービスコンテナにも登録してます。
せっかくサービスコンテナにインスタンスを登録して、抽象に依存させたのに、コントローラーで具象してしまうと、そこに依存してしまいます。

自分はこれらのやってはいけないことを思いっきりやってしまい、サービスコンテナ、Laravelの仕様が全くわかってないことがバレ、白い目で見られました。

「わざわざ抽象化させてるのに、それを使わずに具象させてどーすんねん」と。

正しくは下記のように利用します。

1. インターフェイス
/app/Todo/TodoRepositoryInterface.php


2. インターフェイスを実装したクラス

todo = $todo;
    }

    /**
     * Todoを全件取得
     *
     * @return array
     */
    public function getAll()
    {
        $todos = $this->todo->where('active', 'Active')
                            ->orderBy('updated_at', 'desc')
                            ->get();

        return $todos;
    }

    /**
     * Todoを新規作成する
     *
     * @param todo
     * @param active
     * @return object
     */
    public function store($todo, $active)
    {
        $this->todo->todo   = $todo;
        $this->todo->active = $active === 'on' ? 'Active' : 'Inactive';
        $this->todo->save();
    }

    /**
     * IDに紐づくTodoを取得
     *
     * @param $id
     * @return TodoEntity
     */
    public function show($id)
    {
        return $this->todo->findOrFail($id);
    }
}

3. サービスコンテナに登録

/config/app.php でキー "provider" にあるのが、サービスコンテナに登録されます。

今回はAppServiceProvider.php に登録します。

/app/Providers/AppServiceProvider.php

app->bind(
            \App\Todo\TodoRepositoryInterface::class,
            \App\Todo\TodoRepository::class
        );
    }
}

これでサービスコンテナに登録されました。
このようにサービスコンテナに登録することを「bind(バインド)する」といいます。

そして、利用することを「解決(resolve)する」といいます。

解決の仕方は、よく言われる「DI(Dependancy Injection)」で、2通りあります。

・コンストラクタインジェクション
・メソッドインジェクション

作成したインターフェイスを use し、引数にタイプヒンティングで渡して、使用します。

・コンストラクタインジェクション

todoRepository = $todoRepository;
    }

    /*
    * Todo 一覧を表示する
    */
    public function index()
    {
      $todos = $this->todoRepository->getAll();

      return view('todo.index', compact('todos'));
    }

・メソッドインジェクション

getAll();

      return view('todo.index', compact('todos'));
    }

以上、サービスコンテナに登録したインスタンスを正しく利用する、でした。

参考:
Laravelのここがすごい:
https://qiita.com/nunulk/items/78d70ac809948b470bbc#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A

ひとこと

一般的なのMVCの書き方しか知らなかった自分にとってはこれが新鮮で、だからLaravel は new と書くことが少ないのか、と思いました。引き続き勉強しようと思います。この記事をお読み頂いた皆様方に置きましては、サービスコンテナに登録してるインタンスをコントローラーで new するなどということをして、呆れられないようご注意くださいませ。。

スポンサーリンク

Posted by nobuhiro harada