Contracts
Laravel’s contract is a set of interfaces that define the core services provided by the framework. For example, we have mentioned in the chapter introducing user authentication The User Guard ContractIllumninateContractsAuthGuard
and the User Provider ContractIlluminateContractsAuthUserProvider
as well as the IlluminateContractsAuthAuthenticatable
# implemented by the App\User model that comes with the framework ##contract.
Why use contracts
We can see from the source code files of the above contracts that the contract provided by Laravel is a set of interfaces defined for the core module . Laravel provides corresponding implementation classes for each contract. The following table lists the implementation classes provided by Laravel for the three contracts mentioned above. So in your own development project, if the user authentication system provided by Laravel cannot meet your needs, you can define the implementation classes of the guard and user provider according to your needs, such as The project I worked on before was that user authentication relied on the API of the company's employee management system, so I wrote the implementation class of the guard and user provider contract myself, and let Laravel complete user authentication through the custom Guard and UserProvider. We have introduced the method of customizing user authentication in the chapter introducing user authentication. Readers can read that article. So the purpose of Laravel defining contract interfaces for all core functions is to allow developers to define their own implementation classes according to the needs of their own projects, and for consumers of these interfaces (such as: Controller, or the kernel provides AuthManager, etc.) They do not need to care about how the methods provided by the interface are implemented. They only care about what functions the interface methods can provide and then use these functions. We can change the implementation class for the interface when necessary according to needs. There is no need to make any changes on the consumer side.Define and use contracts
What we mentioned above are all contracts provided by the Laravel kernel. When developing large projects, we can also define contracts in the project ourselves. and implementation classes. You may feel that the built-in Controller and Model layers are enough for you to write code. Adding additional contracts and implementation classes out of thin air will make development cumbersome. Let's start with a simple example and consider what's wrong with the following code:class OrderController extends Controller { public function getUserOrders() { $orders= Order::where('user_id', '=', \Auth::user()->id)->get(); return View::make('order.index', compact('orders')); } }
Separation Of Concerns
Every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class.Each class should have only a single responsibility, and everything in the responsibility should be encapsulated by this classNext we define an interface and then implement the interface
interface OrderRepositoryInterface { public function userOrders(User $user); } class OrderRepository implements OrderRepositoryInterface { public function userOrders(User $user) { Order::where('user_id', '=', $user->id)->get(); } }
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')); } }
Interface and Team Development
When your team is developing a large application, different parts have different development speeds. For example, one developer is developing the data layer, and another developer is working on the controller layer. The developer who wrote the controller wants to test his controller, but the data layer development is slow and cannot be tested simultaneously. If two developers can first reach an agreement in the form of an interface, various classes developed in the background will follow this agreement. Once the agreement is established, even if the agreement has not been implemented, the developer can also write a "fake" implementation for this interfaceclass DummyOrderRepository implements OrderRepositoryInterface { public function userOrders(User $user) { return collect(['Order 1', 'Order 2', 'Order 3']); } }
App::singleton('OrderRepositoryInterface', 'DummyOrderRepository');
RedisOrderRepository.
那么使用IoC容器切换接口实现,应用就可以轻易地切换到真正的实现上,整个应用就会使用从Redis读出来的数据了。
接口与测试
建立好接口约定后也更有利于我们在测试时进行Mock
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']); }
总结
接口在程序设计阶段非常有用,在设计阶段与团队讨论完成功能需要制定哪些接口,然后设计出每个接口具体要实现的方法,方法的入参和返回值这些,每个人就可以按照接口的约定来开发自己的模块,遇到还没实现的接口完全可以先定义接口的假实现等到真正的实现开发完成后再进行切换,这样既降低了软件程序结构中上层对下层的耦合也能保证各部分的开发进度不会过度依赖其他部分的完成情况。
更多laravel框架相关技术文章,请访问laravel教程栏目!
The above is the detailed content of Parsing the Contracts contract under the Laravel framework. For more information, please follow other related articles on the PHP Chinese website!