A detailed explanation of contracts in laravel framework

Time:2021-4-6

Contracts

Laravel’s contract is a set of interfaces that define the core services provided by the framework, such as the user watcher contract we found in the chapter introducing user authenticationIllumninateContractsAuthGuard And user provider contractIlluminateContractsAuthUserProviderAs well as the app user model of the frameworkIlluminateContractsAuthAuthenticatableContract.

Why use contracts

From the source code files of the above contracts, we can see that the contracts provided by laravel are a set of interfaces defined for the core module. Laravel provides the corresponding implementation classes for each contract. The following table lists the implementation classes provided by laravel for the three contracts mentioned above.

So in my own development project, if the user authentication system provided by laravel can’t meet the requirements, you can define the implementation class of watcher and user provider according to the requirements. For example, the project I did before is that user authentication depends on the API of the company’s employee management system, so I wrote the implementation class of watcher and user provider contract by myself, so that laravel can implement the contract through self authentication Define the guard and userprovider to complete user authentication. The method of user-defined authentication has been introduced in the chapter of user authentication. Readers can browse the article.

Therefore, laravel defines contract interfaces for all core functions to enable developers to define their own implementation classes according to their own project needs. For consumers of these interfaces (such as controller or authmanager provided by kernel), they do not need to care about how the methods provided by interfaces are implemented, We only care about the functions provided by the methods of the interface, and then use these functions. We can change the implementation class for the interface when necessary according to the requirements, and the consumer side does not need to make any changes.

Defining and using contracts

What we mentioned above are all contracts provided by laravel kernel. When developing large-scale projects, we can also define contracts and implementation classes in our own projects. You may feel that the two layers of controller and model are enough for you to write code. The extra contracts and implementation classes will make the 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'));
 }
}

This code is very simple, but if we want to test this code, we will definitely contact with the actual database.

In other words, ORM and the controller are tightly coupled. If we don’t use eloquent ORM and connect to the actual database, we can’t run or test this code. This code also violates the software design principle of “separation of concerns”.

In short: this controller knows too much.

The controller doesn’t need to know where the data comes from, just how to access it. The controller doesn’t need to know where the data is from mysql, just that the data is currently available.

Separation of concerns

Every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class.

Each class should have a single responsibility, and everything in the responsibility should be encapsulated by this class

Next, we define an interface and implement it


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

Bind the implementation of the interface to laravel’s service container

App::singleton(‘OrderRepositoryInterface’, ‘OrderRespository’);  

Then we inject the implementation of the interface into our controller


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'));
 }
}

Now our controller has nothing to do with the data level. Here, our data may come from mysql, mongodb or redis. Our controllers don’t know and don’t need to know the difference. In this way, we can test the web layer independently of the data layer, and it will be easy to switch the storage implementation in the future.

Interface and team development

When your team is developing large-scale applications, different parts have different development speeds.

For example, one developer is working on the data layer, and another developer is working on the controller layer.

The developer who writes controller wants to test his controller, but the development of data layer is slow, so it can’t test synchronously. If two developers can reach an agreement in the way of interface first, all kinds of classes developed in the background will follow this agreement.

Once a contract is established, even if the contract is not implemented, the developer can write a “fake” implementation for the interface


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

Once the fake implementation is written, it can be bound to the IOC container

App::singleton(‘OrderRepositoryInterface’, ‘DummyOrderRepository’);

Then the view of the application can be filled with fake data. Next, once the background developer has finished writing the real implementation code, such as redisorderrepository.

Then, with the IOC container switching interface implementation, the application can easily switch to the real implementation, and the whole application will use the data read from redis.

Interface and test

After setting up the interface agreement, it is also more conducive for us to mock when testing


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

summary

Interfaces are very useful in the programming stage. In the design stage, discuss with the team what interfaces need to be made to complete the functions, and then design the specific implementation methods, input parameters and return values of each interface. Everyone can develop their own modules according to the interface conventions. When encountering interfaces that have not yet been implemented, they can completely define the fake implementation of the interface until the real implementation After the development is completed, the switch is implemented, which not only reduces the coupling between the upper layer and the lower layer in the software program structure, but also ensures that the development progress of each part does not depend too much on the completion of other parts.

So far, this article about the analysis of contracts under the laravel framework is introduced here. For more related laravel contracts, please search previous articles of developer or continue to browse the following related articles. I hope you can support developer more in the future!

Recommended Today

Third party calls wechat payment interface

Step one: preparation 1. Wechat payment interface can only be called if the developer qualification has been authenticated on wechat open platform, so the first thing is to authenticate. It’s very simple, but wechat will charge 300 yuan for audit 2. Set payment directory Login wechat payment merchant platform( pay.weixin.qq . com) — > Product […]