正文
return $user;
}
}
class UserRepository
{
protected $userModel, $logModel;
public function __construct(User $user, Log $log)
{
$this->userModel = $user;
$this->logModel = $log;
}
public function getUserById($id)
{
return $this->userModel->findOrFail($id);
}
public function logSession($user)
{
$this->logModel->user = $user->id;
$this->logModel->save();
}
}
在上面的示例中,UserService被注入到了SiteController,UserRepository被注入到了UserService,而AR模型AR和Logs则被注入到了UserRepository类中。这个容器的代码相当直截了当,所以让我们来讨论一下这五层结构。
现代MVC框架,像Laravel和Yii,帮你承担了传统控制器中很多的挑战:当框架处理路由和HTTP谓词规则时,输入验证和预过滤器被移到了应用程序的另外一部分(在Laravel中称为中间层,而在Yii则称为行为)。留下很小一部分功能要程序员编进控制器。
控制器的本质是获取一个请求,然后分发对应的结果。控制器不应该包含任何业务逻辑,否则很难重用代码或者改变应用程序沟通的方式。例如你需要创建一个API而不是渲染视图,如果控制器不包含任何逻辑,那么你只需要改变数据返回的方式即可。
这个瘦瘦的控制器经常会让程序员感到困惑,此外,由于控制器是一个默认的层并作为最高入口点,很多程序员只是一味地往控制器添加新代码,而丝毫不考虑任何架构。结果,添加了过多的职责,一如:
●
业务逻辑(使重用业务逻辑代码变得有可能)
● 直接改变模型状态(这种情况下,数据库的任何改变都会导致各处代码发生巨大的改变。译者注:可谓牵一发而动全身)
● 模型关系逻辑(例如复杂查询,多个模型的关联;再一次,如果数据库或者关系逻辑发生改变,我们将不得不在全部控制器中修改它)。
// 一个糟糕的控制器示例
public function user(Request $request)
{
$user = User::where('id', '=', $request->id)
->leftjoin('posts', function ($join) {
$join->on('posts.user_id', '=', 'user.id')
->where('posts.status', '=', Post::STATUS_APPROVED);
})
->first();
if (!empty($user)) {
$user->last_login = date('Y-m-d H:i:s');
} else {
$user = new User();
$user->is_new = true;
$user->save();
}
return view('user.index', compact('user'));
}
●
它包含了太多业务逻辑。
●它直接使用了Active Record,所以如果你改变了数据库中的某些东西,像重命名last_login字段,你不得不在全部控制器中修改它。
●它知道了数据库中的关系,所以如果数据库中的某些东西发生变化了我们也不得不相应做出修改。
●它是不可重用的,导致了代码重复。
控制器应该是苗条的;真的,它要做的全部事就是接收请求然后返回结果。这是一个好的例子:
// 一个好的控制器示例
public function user (Request $request)
{
$user = $this->userService->getUserById($request->id);
return view('user.index', compact('user'));
}