Laravel框架下的Contracts契约详解

2020-03-17 14:01:18于丽

控制器不需要去了解数据是从哪儿来的,只要知道如何访问就行。控制器也不需要知道这数据是从MySQL或哪儿来的,只需要知道这数据目前是可用的。

Separation Of Concerns 关注分离

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

每个类都应该只有单一的职责,并且职责里所有的东西都应该由这个类封装

接下来我们定义一个接口,然后实现该接口

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层了,将来切换存储实现也会很容易。

接口与团队开发

当你的团队在开发大型应用时,不同的部分有着不同的开发速度。

比如一个开发人员在开发数据层,另一个开发人员在做控制器层。

写控制器的开发者想测试他的控制器,不过数据层开发较慢没法同步测试。那如果两个开发者能先以interface的方式达成协议,后台开发的各种类都遵循这种协议。

一旦建立了约定,就算约定还没实现,开发者也可以为这接口写个“假”实现

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读出来的数据了。

接口与测试

建立好接口约定后也更有利于我们在测试时进行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']);
 } 								 
			 
相关文章 大家在看