我有一个关于存储相当复杂的应用程序逻辑的最佳位置的问题。
假设我想允许用户登录网站。登录过程应包括以下步骤:
- 在表单字段中,对用户的电子邮件进行哈希处理
- 在身份验证表中查找用户的电子邮件哈希,以确保用户存在(身份验证表仅存储加密的电子邮件、电子邮件哈希、user_id、和密码哈希)
- 如果找到用户,则验证其密码
- 重新生成会话 ID
- 将新会话存储在数据库中
使用数据映射器模式,我有以下三个模型参与此过程
/User/
- User.php
- UserMapper.php
/Auth/
- Auth.php
- AuthMapper.php
/Session/
- Session.php
- SessionMapper.php
因此,登录用户的函数如下所示:
function login($email, $password)
{
$security = new 'Lib'Security;
$authMapper = new 'Models'Auth'AuthMapper($this->db);
$userMapper = new 'Models'User'UserMapper($this->db);
$session = new 'Models'Session'Session;
$sessionMapper = new 'Models'Session'SessionMapper($this->db);
$email_hash = $security->simpleHash($email);
if (!$auth = $authMapper->fetchWhere('email_hash', $email_hash))
{
echo 'User doesnt exist';
return;
}
if (!$auth->verifyPassword($password))
{
echo 'Password not correct';
return;
}
$user = $userMapper->fetchById($auth->user_id);
$session->createUserSession($user);
$sessionMapper->save($session);
}
这里有一些问题。首先是缺乏依赖注入。第二个是,这是一个繁琐的代码块,可以使用我可能想要提供登录功能的每个地方。
那么这个逻辑应该在哪里呢?在控制器中?在用户域对象中?在身份验证域对象中?这似乎有点循环 - 数据映射器的全部意义在于域对象甚至不处理自身的持久性,更不用说其他对象了......它应该放置在/User/或/Auth/模型中的用户或身份验证服务层中吗?
我对这种事情的最佳实践有点迷茫。
另外请记住,我这样做是为了学习目的,所以我不想只使用像Symfony这样的东西。
为了回答我自己的问题,我决定最好的地方是创建一个接受LoginHandlerInterface
接口作为构造函数参数的AccountController
。
然后,帐户控制器如下所示:
namespace App'Controllers;
class AccountController
{
protected $LoginHandler;
public function __construct('Framework'Interfaces'LoginHandlerInterface $LoginHandler)
{
$this->LoginHandler = $LoginHandler;
}
public function login()
{
if (/* ... form validation stuff ... */)
{
try
{
$this->LoginHandler->login($email, $password);
}
catch ('Framework'Exceptions'Login $e)
{
// Assign login errors to template etc...
}
}
}
}
然后,无论我最终使用哪种LoginHandler
,它都有完成所有登录所需的一切(查找用户,验证密码,更新会话等)。这使我的AccountController
保持干净、灵活和可测试。
我通过自动解析构造函数依赖项的 IoC 容器中的配置注入所需的LoginHandler
(和RegistrationHandler
,我在这里没有显示)。
身份验证应该处理登录,如果它失败返回 false, 如果为 true,则执行会话的逻辑并返回 true。
所以在你的控制器中,你会做类似if(Auth->login($email,$password))
ps:对于这种类型的工作流程,我更喜欢使用单例模式(因为它破坏了单元测试),但我确实认为它更适合您。