본 글은 Larave 프레임워크에서의 Contract 분석에 관한 내용으로, 도움이 필요한 친구들이 참고하시면 좋을 것 같습니다.
Contracts
Laravel의 계약은 사용자 가드 계약 IllumninateContractsAuthGuard 및 사용자 공급자 계약 IlluminateContractsAuthUserProvider
와 같이 프레임워크에서 제공하는 핵심 서비스를 정의하는 인터페이스 세트입니다. 사용자 인증을 소개하는 장 AppUser
모델은 IlluminateContractsAuthAuthenticatable 계약을 구현합니다.
계약을 사용하는 이유
위 계약의 소스 코드 파일을 통해 Laravel에서 제공하는 계약이 핵심 모듈에 대해 정의된 인터페이스 집합임을 알 수 있습니다. Laravel은 각 계약에 해당하는 구현 클래스를 제공합니다. 다음 표에는 위에서 언급한 세 가지 계약에 대해 Laravel이 제공하는 구현 클래스가 나열되어 있습니다.
Contract | Laravel 커널에서 제공되는 구현 클래스 |
---|---|
IllumninateContractsAuthGuard | IlluminateAuthSessionGuard |
IlluminateContractsAuthUserProvide | IlluminateAuthEloquentUserProvider |
IlluminateContractsAuthAuthenticatable | IlluminateFoundationAuthAuthenticatable(사용자 모델의 상위 클래스) |
그래서 자신의 개발 프로젝트에서 Laravel에서 제공하는 사용자 인증 시스템이 요구 사항을 충족할 수 없는 경우 필요에 따라 가드 및 사용자 공급자의 구현 클래스를 정의할 수 있습니다. 예를 들어 제가 이전에 작업한 프로젝트는 해당 사용자였습니다. 인증은 회사의 직원 관리 API에 의존했기 때문에 Guard 및 User Provider Contract의 구현 클래스를 직접 작성하여 Laravel이 맞춤형 Guard 및 UserProvider를 통해 사용자 인증을 완료할 수 있도록 했습니다. 사용자 인증을 소개하는 장에서 사용자 인증을 사용자 정의하는 방법을 소개했습니다. 독자는 해당 기사를 읽을 수 있습니다.
그래서 Laravel이 모든 핵심 기능에 대한 계약 인터페이스를 정의하는 목적은 개발자가 자신의 프로젝트 요구 사항과 이러한 인터페이스(예: 커널에서 제공하는 Controller 또는 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에서 어디서 왔는지 알 필요가 없으며, 데이터가 현재 사용 가능하다는 것만 알면 됩니다.
관심 사항 분리모든 클래스는 단일 책임을 가져야 하며 해당 책임은 클래스에 의해 완전히 캡슐화되어야 합니다.
모든 클래스는 단일 책임만 가져야 하며 책임의 모든 내용은 이 클래스 캡슐화로 캡슐화되어야 합니다.
다음으로 인터페이스를 정의한 다음 인터페이스를 구현합니다
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에서 가져올 수 있습니다. 우리 컨트롤러는 차이점을 모르고 알 필요도 없습니다. 이렇게 하면 데이터 계층과 독립적으로 웹 계층을 테스트할 수 있으며 향후 스토리지 구현을 쉽게 전환할 수 있습니다.
인터페이스 및 팀 개발
팀이 대규모 애플리케이션을 개발할 때 부분마다 개발 속도가 다릅니다. 예를 들어 한 개발자는 데이터 레이어를 개발하고 다른 개발자는 컨트롤러 레이어를 개발하고 있습니다. 컨트롤러를 작성한 개발자는 컨트롤러를 테스트하고 싶지만 데이터 레이어 개발이 느리고 동시에 테스트할 수 없습니다. 두 개발자가 먼저 인터페이스 형태로 합의하면 백그라운드에서 개발되는 모든 클래스는 이 합의를 따릅니다. 계약이 체결되면 계약이 아직 구현되지 않았더라도 개발자는 이 인터페이스에 대한 "가짜" 구현을 작성할 수 있습니다
class DummyOrderRepository implements OrderRepositoryInterface { public function userOrders(User $user) { return collect(['Order 1', 'Order 2', 'Order 3']); } }
가짜 구현이 작성되면 IoC 컨테이너에 바인딩될 수 있습니다
App::singleton('OrderRepositoryInterface', 'DummyOrderRepository');
그런 다음 그런 다음 애플리케이션이 가짜 데이터로 뷰를 채울 수 있습니다. 다음으로 백엔드 개발자가 RedisOrderRepository라는 실제 구현 코드 작성을 완료하면 다음과 같습니다. 그런 다음 IoC 컨테이너 전환 인터페이스 구현을 사용하면 애플리케이션이 실제 구현으로 쉽게 전환할 수 있으며 전체 애플리케이션은 Redis에서 읽은 데이터를 사용합니다.
인터페이스 및 테스트
인터페이스 계약을 체결한 후에는 테스트 중에 모의하는 것이 더 편리할 것입니다.
public function testIndexActionBindsUsersFromRepository() { // Arrange... $repository = Mockery::mock('OrderRepositoryInterface'); $repository->shouldReceive('userOrders')->once()->andReturn(['order1', 'order2]); App::instance('OrderRepositoryInterface', $repository); // Act... $response = $this->action('GET', 'OrderController@getUserOrders'); // Assert... $this->assertResponseOk(); $this->assertViewHas('order', ['order1', 'order2']); }
요약
인터페이스는 프로그래밍 단계에서 매우 유용합니다. 기능을 완성하기 위해 팀은 어떤 인터페이스를 공식화해야 하며, 각 인터페이스에 대해 구현할 특정 메소드, 메소드의 입력 매개변수 및 반환 값 등을 설계해야 합니다. 누구나 인터페이스에 따라 자신의 모듈을 개발할 수 있습니다. 아직 구현되지 않은 인터페이스가 나타나면 먼저 인터페이스를 정의할 수 있습니다. 가짜 구현은 전환하기 전에 실제 구현 개발이 완료될 때까지 기다립니다. 이는 소프트웨어 프로그램의 상위 계층과 하위 계층 간의 결합을 감소시킬 뿐만 아니라 구조는 물론 각 부분의 개발 진행이 다른 부분의 완성도에 지나치게 의존하지 않도록 보장합니다.
위 내용은 Larave 프레임워크에서의 계약 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!