我正在开发一个使用面向对象方法的新应用程序,其中涉及一些REST,我没有使用任何框架。
我遇到的问题是在下面的setter中验证用户输入的最佳位置:
public function setSalary($salary)
{
if (Validator::money($salary))
$this->salary = $salary;
else
return 'Error that is an invalid number';
}
还是在控制器中?
public function updateSalary()
{
$errors = array();
if (Validator::money($_POST['salary']))
$salary = $_POST['salary'];
else
$errors ['salary'] = 'Error that is an invalid number';
if(count($errors))
return $errors;
$employee = new Employee($_POST['e_Id']);
$employee->setSalary($salary);
$employee->save();
}
如果我要插入setter,我的控制器应如何显示,并返回验证错误?
我已经看到大多数人在控制器中进行验证,但我认为应该是验证的模型,因为它将使用数据,我们可以重用该模型而不重复自己。 但是,有时候验证规则可能需要在某些特殊情况下有所不同,例如对不同视图的不同验证或对晚餐管理员的不同验证。
您认为哪一个符合最佳做法?
答案 0 :(得分:7)
首先,由于您似乎希望实现类似MVC的结构,让我们从一些常见错误开始,这些错误与验证无直接关系。
只有部分代码(包含PHP超级全局)应该是引导阶段。在你的代码中撒满了超级全局,这使得测试变得非常困难。您的代码也会通过<input>
名称与您的HTML紧密结合。
控制器不应该有任何逻辑,也不应该处理数据保存。阅读this post,也许它会清除一些内容。
好的..现在回到原来的主题。
一般来说,有两种思想流派:
您在域实体中进行验证
您的域实体(在您的情况下为Employee
)包含与其相关的所有业务角色。如果它处于有效状态,它可以使用这些规则进行评估。
代码会是这样的:
$employee = new Entity\Employee;
$employee->setID($id);
$employee->setSalary($money);
if ($employee->isValid()) {
$mapper = new Mapper\Employee($dbConn);
$mapper->store($emplyee);
}
您永远不会创建无效的域名实体
此方法来自DDD,其中您的域实体由其他类创建,并且它只能从一个有效状态更改为另一个有效状态。基本上,如果你想探索这种方法,你必须阅读this book(可能好几次)。
此外,还有另一个验证表单,前两个说明涵盖了注释:数据完整性检查。这是验证的类型,实际上是我的RDBMS。例如,UNIQUE
约束。
当您遇到ans完整性违规时,它通常会抛出您在服务层中处理的异常。
答案 1 :(得分:1)
每次向数据库写入数据时都必须调用验证。所以在这种情况下来自控制器。实际验证发生在模型中。模型是对象,它知道它的字段遵循哪些规则,并且可以检查数据是否有效。此外,该模型是世界其他地方和数据库之间的边界。所以,我会做这样的事情:
public function updateSalary()
{
$employee = new Employee($_POST['e_Id']);
$employee->setSalary($_POST['salary']));
if ($employee->validate()) {
$employee->save();
} else {
return $employee->getErrors();
}
}
为什么我这样给你:
答案 2 :(得分:0)
取决于您,如果验证规则是“全局”的,换句话说,如果每次更新数据库表/对象适当时它们是相同的,则将它们放在模型中,否则验证控制器中的用户输入在不同的情况下,您需要为同一个实体提供不同的验证规则。
答案 3 :(得分:0)
首先,我不是下面的怪人就是我的想法。
它应该在控制器中完成,只是因为现在你只是验证号码,这只是简单的检查,我认为你只需要为此应用正则表达式。
我实际上理解的是,模型是您保持业务逻辑的地方,但如果您的字段值总是错误的,那么您永远不会处理业务逻辑,并且您不希望您的模型发挥作用。
答案 4 :(得分:0)
我建议尽可能在模型中应用验证。它的优点是可以以更完整的方式直接测试模型,并保证模型只保留有效数据。
当然,Controller需要处理验证,并且可能是第一个在涉及分布式项目的复杂验证时调用验证的层。但是在你给出的例子中没有这样的复杂性。
请注意,无论如何,某些验证甚至会由数据库引擎执行(例如require('models/user')
和主键要求)。
我还建议在模型中使用异常,因为这可以保证运行函数的中断,并允许您在Controller中以类似的方式处理所有(验证)错误。我建议配置数据库访问层以触发异常。如果是PDO,您可以按如下方式进行:
node_modules
在模型中,您将在验证失败时抛出异常:
NOT NULL
在Controller中你会发现错误并记录它们:正如你在 $ errors 中所做的那样,但是我会将它们保留在模型中,以便以后访问View。这说明了模型如何检测验证错误,但Controller处理它。
我还建议不要直接创建一个Employee实例,而是让Model为你做这个:
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
使用发布的参数调用后一个函数,因为这可以更好地指示该方法用作输入的内容。顶级PHP代码如下所示:
public function setSalary($salary) {
if (!Validator::money($salary)) {
throw new Exception('Invalid value provided as salary.');
}
$this->salary = $salary;
}
View将访问记录的错误以将其报告给客户端。
我意识到关于在哪里检测验证错误,在哪里处理它们,何时触发异常(以及什么时候没有)等等的争论将永远不会结束。但这对我有用。