Dependency Injection 依赖注入
laravel 框架的基础是:IoC Container (控制反转容器)、控制反转的"容器” 是方便实现“依赖注入”的工具、但实现依赖注入并不一定需要控制反转容器、只是使用“容器”会方便和容易一点
#控制反转
class UserController extends BaseController{ public function getIndex() { $users= User::all(); return View::make('users.index', compact('users')); } }如果测试這段代码就需跟实际的数据库发生联系、即Eloquent ORM 跟改控制器有紧耦合,违背了“关注分离”软件设计的原则、简单讲:這个控制器知道太多了。
控制器不需要了解数据从哪里来,只知道如何访问、和这数据是可用的即可
Separation Of Concerns 关注分离 Every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class. 每一个类都应该有单独的职责,并且该职责应完全被这个类封装。(译者注:我认为就是不要让多个类负责同样的职责)
例如:一台显示器、用很多连接的线缆接口(HDMI、VGA、DVI)、你可以通过不同的接口访问该显示器的功能。Internet 就像一个线缆连接你的应用程序、大部分显示器的功能是独立于线缆的,线缆(比如 HTTP)只是你应用程序的一种传输机制、所以不想把传输机制(控制器)和业务逻辑混在一起。這样的好处就是其他的传输机制比如:API调用、移动应用等都可以访问我们的业务逻辑
所以就别把控制器和Eloquent ORM 耦合在一起了,咱们添加(注入)一个 Repository 类
#建立协议
定义一个接口、然后实现它
interface UserRepositoryInterface { public function all(); } class DbUserRepository implements UserRepositoryInterface { public function all() { return User::all()->toArray(); } }
class UserController extends BaseController { public function __construct(UserRepositoryInterface $users) { $this->users = $users; } public function getIndex() { $users=$this->users->all(); return View::make('users.index', compact('users')); } }這样控制跟数据层面就无关了,无知就是福!数据可能来之MySql、MongoDB 或者Redis 、控制器不知道也不关注他们的区别、這个小小的改变就让web 层独立 Data 层,将来切换存储也很容易.
#写一个测试案例、首先模拟一个Repository 和绑定它到 应用 IoC 容器中、然后要保证控制器正确的调用這个Repository(数据仓库)
public function testIndexActionBindsUsersFromRepository() { // Arrange... $repository = Mockery::mock('UserRepositoryInterface'); $repository->shouldReceive('all')->once()->andReturn(array('foo')); App::instance('UserRepositoryInterface', $repository); // Act... $response = $this->action('GET', 'UserController@getIndex'); // Assert... $this->assertResponseOk(); $this->assertViewHas('users', array('foo')); }
Are you Mocking Me 你在模仿我么? In this example, we used the `Mockery` mocking library. This library provides a clean, expressive interface for mocking your classes. Mockery can be easily insalled via Composer. 在上面的例子里, 我们使用了名为`Mockery`的模仿库。 这个库提供了一套整洁且富有表达力的方法,用来模仿你写的类。 Mockery可以通过Composer安装。