Php 锂和验证复杂表单输入-如何?

Php 锂和验证复杂表单输入-如何?,php,validation,cakephp,model-view-controller,lithium,Php,Validation,Cakephp,Model View Controller,Lithium,我已经做了很多Lili教程(下面的链接,以防它们对其他人有所帮助,同时也表明我已经完成了家庭作业:),我了解了创建模型、视图、控制器以及使用MVC基于表单输入创建DB记录的最基本部分 然而,我对MVC的webapps和limition还不熟悉,我不确定在更复杂的情况下应该如何编写代码。这是一个一般性问题,但我有两个具体的验证问题: 如何验证表单中提交的日期数据 我应该如何检查两个用户电子邮件字段是否具有相同的值 我将非常感谢在这些问题上的任何帮助,像这样的具体例子也将真正帮助我理解如何在其他

我已经做了很多Lili教程(下面的链接,以防它们对其他人有所帮助,同时也表明我已经完成了家庭作业:),我了解了创建模型、视图、控制器以及使用MVC基于表单输入创建DB记录的最基本部分

然而,我对MVC的webapps和limition还不熟悉,我不确定在更复杂的情况下应该如何编写代码。这是一个一般性问题,但我有两个具体的验证问题:

  • 如何验证表单中提交的日期数据
  • 我应该如何检查两个用户电子邮件字段是否具有相同的值
我将非常感谢在这些问题上的任何帮助,像这样的具体例子也将真正帮助我理解如何在其他情况下做好MVC编码

日期输入-验证跨多个表单输入拆分的数据 出于用户界面的原因,注册表单要求用户在三个字段中输入他们的DOB:

<?=$this->form->field('birthday', array('type' => 'select', 'list' => array(/*...*/))); ?>
<?=$this->form->field('birthmonth', array('type' => 'select', 'list' => array(/*...*/))); ?>
<?=$this->form->field('birthyear', array('type' => 'select', 'list' => array(/*...*/))); ?>
如何编写automagic验证规则来检查这两个表单字段是否具有相同的值,但仅将电子邮件地址保存到数据库

这感觉和上面的问题差不多,因为我能想到的可能答案列表是一样的-所以我把这作为一个问题提交,但我真的很感谢你对这两个部分的帮助,因为我认为这个问题的解决方案将是微妙的,不同的,同样有启发性的

[编辑:与此密切相关的是未将验证电子邮件地址存储到我的模型和数据库中的问题]

关于锂的背景阅读 我也读过其他的书,但这三本教程让我了解了我现在的用户和注册表单

其他一些与主题密切相关的问题(但没有回答,也没有针对具体问题)

  • 一个答案是建议创建一个单独的控制器(以及模型和…?)-它对我来说感觉不是很“锂”,我担心它可能很脆弱/很容易出现故障
  • 我确信我担心把它放进控制器是对的,但我不确定什么是好的解决方案
  • 这让我觉得我应该把它放在模型里,但我不知道用锂电池做这件事的最佳方法(见上面日期项下我的项目列表)
  • Scribd的演讲问了我希望在最后一页回答的问题。。。于是它停了下来,没有回答

注:CakePHP风格的答案也不错。我不知道,但它是相似的,我相信我可以从它翻译,如果我需要

我建议在
模型
中执行此操作,而不是在
控制器
中执行此操作-这样无论从何处执行保存操作都会发生

对于日期字段问题,在您的模型中,重写
save()
方法,并在调用
parent::save
进行实际保存之前,处理将数据中的多个字段转换为一个日期字段的问题。任何高级操作都可能发生在那里

在您的评论中描述的使用隐藏表单字段获取错误消息以显示的技术听起来相当不错

为了比较这两个电子邮件字段是否相等,我建议定义一个自定义验证器。您可以在引导程序中使用

然后在您的模型中:

public $validates = array(
    "email" => array(
        "match",
        "message" => "Please re-type your email address.",
        "against" => "email2"
    )
);
编辑:根据注释,以下是在控制器中执行自定义规则验证的方法:

public function save() {
    $entity = MyModel::create($this->request->data);
    $rules = array(
        "email" => array(
            "match",
            "message" => "Please re-type your email address.",
            "against" => "email2"
        )
    );

    if (!$entity->validates($rules)) {
        return compact('entity');
    }

    // if your model defines a `$_schema` and sets `$_meta = array('locked' => true)`
    // then any fields not in the schema will not be saved to the db

    // here's another way using the `'whitelist'` param
    $blacklist = array('email2', 'some', 'other', 'fields');
    $whitelist = array_keys($entity->data());
    $whitelist = array_diff($whitelist, $blacklist);

    if ($entity->save(null, compact('whitelist'))) {
        $this->redirect(
            array("Controller::view", "args" => array($entity->_id)),
            array('exit' => true)
        );
    }

    return compact('entity');
}

将数据设置为实体的优点是,如果出现验证错误,将自动在表单中预先填充数据。

与SofaCitizen讨论的总结(2012-04-01):提交的数据应在控制器中进行后处理。这是因为模型存储的是日期,而不是构成日期的三个单独字段。将验证信息传递回视图有点困难,但一种解决方案是在3个日期输入字段之后向表单添加一个“DOB”字段。将此“DOB字段显示”设置为“无”可能仍允许显示其错误消息(通过代理其他日期字段)。感谢您的回复以及您将其放入模型中以使其在任何地方都可用的建议,这听起来很明智。因为这三个字段现在只是在表单提交中使用,而不是在其他情况下,我将向模型添加一个“processformdata”方法,并将返回值从该方法传递给save函数。你的验证器的想法看起来也很聪明,我从来没有这样想过。有一件事我不明白,
$options['values']
是如何用提交的表单字段填充的。这是自动发生的吗?
$options['values']
是自动发生的。看<代码>$validator::check($entity->data(),$rules,$options)被调用,
$entity->data()
最终被传递到
$options['values']
。这有点复杂,但是在
Validator::check()
中有
$rule+=$options+compact('values')
其中
$values
$entity->data()
,随后
$rule+$options
被传递到
验证器::rule()
。感谢对代码流的澄清和解释。我终于有机会跟进这个问题,只要这两个字段都是模型的一部分,它就可以完美地工作。如果一个仅用于输入验证(例如,电子邮件地址确认,我不想将地址存储两次),则它不起作用。相反,在浏览了代码并与li3上的人讨论了输入与数据验证之后,处理此类验证的最佳方法似乎是在控制器中捕获它,并手动更新
$foo->\u错误
,其中
$foo
create()
返回的
实体
对象。对。。。我只是编辑了我的答案,试图做一些可能是两全其美的事情。它利用了
public $validates = array(
    "email" => array(
        "match",
        "message" => "Please re-type your email address.",
        "against" => "email2"
    )
);
public function save() {
    $entity = MyModel::create($this->request->data);
    $rules = array(
        "email" => array(
            "match",
            "message" => "Please re-type your email address.",
            "against" => "email2"
        )
    );

    if (!$entity->validates($rules)) {
        return compact('entity');
    }

    // if your model defines a `$_schema` and sets `$_meta = array('locked' => true)`
    // then any fields not in the schema will not be saved to the db

    // here's another way using the `'whitelist'` param
    $blacklist = array('email2', 'some', 'other', 'fields');
    $whitelist = array_keys($entity->data());
    $whitelist = array_diff($whitelist, $blacklist);

    if ($entity->save(null, compact('whitelist'))) {
        $this->redirect(
            array("Controller::view", "args" => array($entity->_id)),
            array('exit' => true)
        );
    }

    return compact('entity');
}