ホームページ  >  記事  >  PHPフレームワーク  >  Laravel フレームワークでの Contracts コントラクトの解析

Laravel フレームワークでの Contracts コントラクトの解析

藏色散人
藏色散人転載
2020-01-31 20:08:141986ブラウズ

Laravel フレームワークでの Contracts コントラクトの解析

コントラクト

Laravel のコントラクトは、フレームワークによって提供されるコア サービスを定義するインターフェイスのセットです。ユーザー認証を紹介する章 ユーザー ガード コントラクト IllumninateContractsAuthGuard とユーザー プロバイダー コントラクト IlluminateContractsAuthUserProvider、およびアプリによって実装される IlluminateContractsAuthAuthenticatablecontract フレームワークに付属するユーザー モデル。

コントラクトを使用する理由

上記のコントラクトのソースコードファイルを通じて、Laravel によって提供されるコントラクトは、Laravel 用に定義されたインターフェイスのセットであることがわかります。コアモジュール。 Laravel は、各コントラクトに対応する実装クラスを提供します。次の表は、上記の 3 つのコントラクトに対して Laravel が提供する実装クラスのリストです。

Laravel フレームワークでの Contracts コントラクトの解析

したがって、独自の開発プロジェクトで、Laravel が提供するユーザー認証システムがニーズを満たせない場合は、必要に応じてウォッチャーとユーザープロバイダーの実装クラスを定義できます。以前取り組んだプロジェクトでは、ユーザー認証が会社の従業員管理システムのAPIに依存していたため、ガードとユーザープロバイダーコントラクトの実装クラスを自分で書き、カスタムGuardを介してLaravelにユーザー認証を完了させました。とユーザープロバイダー。ユーザー認証のカスタマイズ方法については、ユーザー認証の紹介の章で紹介していますので、そちらをご覧ください。

つまり、Laravel がすべてのコア機能のコントラクト インターフェイスを定義する目的は、開発者が独自のプロジェクトのニーズに応じて独自の実装クラスを定義できるようにすることと、これらのインターフェイスの利用者 (コントローラー、カーネルは AuthManager などを提供します) インターフェースによって提供されるメソッドがどのように実装されるかを気にする必要はありません。インターフェース メソッドがどのような機能を提供できるかだけを気にし、それらの機能を使用します。必要に応じてインターフェースを変更するだけで、コンシューマ側で変更を加える必要はありません。

コントラクトの定義と使用

上で述べたものはすべて、Laravel カーネルによって提供されるコントラクトです。大規模なプロジェクトを開発する場合、プロジェクト内でコントラクトを自分で定義することもできます。コードを作成するには、組み込みのコントローラー層とモデル層だけで十分だと感じるかもしれませんが、何もないところからコントラクトや実装クラスを追加すると、開発が面倒になります。簡単な例から始めて、次のコードの何が問題なのかを考えてみましょう。

class OrderController extends Controller
{
    public function getUserOrders()
    {
        $orders= Order::where('user_id', '=', \Auth::user()->id)->get();
        return View::make('order.index', compact('orders'));
    }
}

このコードは非常に単純ですが、このコードをテストしたい場合は、間違いなく実際のデータベースと通信することになります。

言い換えれば、ORM とこのコントローラーは密接に結合されています。 Eloquent ORM を使用して実際のデータベースに接続しない限り、このコードを実行またはテストする方法はありません。このコードは、「関心事の分離」というソフトウェア設計原則にも違反しています。

簡単に言うと、このコントローラーは知りすぎています。

コントローラーは、データへのアクセス方法を知っていれば、データがどこから来たのかを知る必要はありません。コントローラーはデータが MySQL からどこから来たのかを知る必要はなく、データが現在利用可能であることを知っていればよいだけです。

#懸念事項の分離

すべてのクラスは 1 つの責任を持つ必要があり、その責任はクラスによって完全にカプセル化される必要があります。

#各クラスは 1 つの責任のみを持つ必要があり、その責任内のすべてがこのクラスによってカプセル化される必要があります。

次にインターフェイスを定義し、インターフェイスを実装します

interface OrderRepositoryInterface 
{
    public function userOrders(User $user);
}
 
class OrderRepository implements OrderRepositoryInterface
{
    public function userOrders(User $user)
    {
        Order::where('user_id', '=', $user->id)->get();
    }
}

の実装をバインドします。 Laravel のサービス コンテナへのインターフェイス

App::singleton('OrderRepositoryInterface', 'OrderRespository');

次に、インターフェイスの実装をコントローラーに注入します

class UserController extends Controller
{
    public function __construct(OrderRepositoryInterface $orderRepository)
    {
        $this->orders = $orderRespository;
    }
   
    public function getUserOrders()
    {
        $orders = $this->orders->userOrders();
        return View::make('order.index', compact('orders'));
    }
}

これで、コントローラーはデータ層から完全に独立しました。ここでのデータは、MySQL、MongoDB、または Redis から取得される可能性があります。私たちのコントローラーは違いを知りませんし、知る必要もありません。こうすることで、データ層から独立して Web 層をテストでき、将来的にはストレージ実装を簡単に切り替えることができます。

インターフェイスとチーム開発

チームが大規模なアプリケーションを開発している場合、部分によって開発速度は異なります。

たとえば、ある開発者がデータ層を開発し、別の開発者がコントローラー層を開発しているとします。

コントローラーを作成した開発者はコントローラーをテストしたいと考えていますが、データ層の開発が遅いため、同時にテストすることができません。 2 人の開発者が最初にインターフェイスの形式で合意に達すると、バックグラウンドで開発されるさまざまなクラスがこの合意に従います。

合意が確立されると、合意が実装されていない場合でも、開発者はこのインターフェイスの「偽の」実装を作成することもできます。

class DummyOrderRepository implements OrderRepositoryInterface 
{
    public function userOrders(User $user)
    {
        return collect(['Order 1', 'Order 2', 'Order 3']);
    }
}

偽の実装が作成されると、 IoC コンテナ内で

App::singleton('OrderRepositoryInterface', 'DummyOrderRepository');

にバインドされると、このアプリケーションのビューに偽のデータを埋め込むことができます。次に、バックエンド開発者が実際の実装コードの作成を完了すると、たとえば、

RedisOrderRepository

と呼ばれます。 <p>那么使用IoC容器切换接口实现,应用就可以轻易地切换到真正的实现上,整个应用就会使用从Redis读出来的数据了。</p> <p><strong>接口与测试</strong></p> <p>建立好接口约定后也更有利于我们在测试时进行<code>Mock

public function testIndexActionBindsUsersFromRepository()
{    
    // Arrange...
    $repository = Mockery::mock(&#39;OrderRepositoryInterface&#39;);
    $repository->shouldReceive(&#39;userOrders&#39;)->once()->andReturn([&#39;order1&#39;, &#39;order2]);
    App::instance(&#39;OrderRepositoryInterface&#39;, $repository);
    // Act...
    $response  = $this->action(&#39;GET&#39;, &#39;OrderController@getUserOrders&#39;);
         
    // Assert...
    $this->assertResponseOk();
    $this->assertViewHas(&#39;order&#39;, [&#39;order1&#39;, &#39;order2&#39;]);
 }

总结

接口在程序设计阶段非常有用,在设计阶段与团队讨论完成功能需要制定哪些接口,然后设计出每个接口具体要实现的方法,方法的入参和返回值这些,每个人就可以按照接口的约定来开发自己的模块,遇到还没实现的接口完全可以先定义接口的假实现等到真正的实现开发完成后再进行切换,这样既降低了软件程序结构中上层对下层的耦合也能保证各部分的开发进度不会过度依赖其他部分的完成情况。

更多laravel框架相关技术文章,请访问laravel教程栏目!

以上がLaravel フレームワークでの Contracts コントラクトの解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。