Yii - 从控制器动态更改规则

7
假设我有一个可以有颜色的产品。根据产品类型,颜色字段可能是必需的或非必需的。
如果颜色总是必需的,那么在产品模型中会有以下内容:
public function rules()
{
    return array(
        array('colour', 'required')
    );
}

然而,我希望这能根据产品类型实现动态变化。

这个应该在控制器中完成吗?我想在控制器中添加如下代码:

public function actionOrder() {
    // ....
    if ($product->HasColour) {
        // set the colour validation to be required
    } else {
        // set the colour validation to be not required
    }
}

如何最好地处理这个问题?

谢谢


如果它是特定于产品类型的,因此属于某个型号,那么应该在该型号中完成。 - Zombaya
但是,如果您正在验证表单输入,则控制器中的操作也是正确的。因此,我想您在这里没有犯错误。 - Zombaya
模型在执行actionOrder()之前不知道产品,对吧? - Adrian Gunawan
我应该在控制器(Controller)中做什么?如何在控制器(Controller)中添加模型(Model)的规则? - Adrian Gunawan
5个回答

15
您可以使用“场景”(scenario)。在模型中:
class Model extends CActiveRecord {
    // ....
    public function rules() {
        return array(
            array('colour', 'required', 'on' => 'hasColour')
        );
    }
    // ....
}

在控制器中:

public function actionOrder() {
    // ....
    $model = new Product();
    if ($product->HasColour) {
        $model->setScenario('hasColour');
    }
}

因此,只有在模型的场景是hasColour时,所需颜色才会得到验证。


唯一的问题是它没有在标签上添加星号 * :( - user2636556

11
class LoginForm extends CFormModel
{
    public $username;
    public $password;
}

$form = new LoginForm();
$form->validatorList->add(
    CValidator::createValidator('required', $form, 'username, password')
);

现在 $form 有两个必填字段。


这并没有真正回答问题。用户正在询问如何处理某些数据在一个场景中是必需的,而在另一个场景中则不是,并且采取什么最佳方法。 - Ren

4
一种方法是使用自定义验证规则。例如,规则如下:
array('colour', 'requiredOnHasColour'),

接下来是同一模型类中的验证器方法:

public function requiredOnHasColour($attribute, $params) {
    if ($this->hasColour && $this->$attribute == null)
        $this->addError($attribute, 'Colour is required.');
}

更多信息:创建您自己的验证规则


1
如果你想要执行更复杂的逻辑,那么场景可能无法满足你的需求。此时,你可以重写 init 方法,在其中执行定义验证规则的所有逻辑,并将结果添加到 $validationRules 数组中。然后在 rules() 方法中返回该数组。就像这样:
 class Person extends CActiveRecord
{
    public function init(){
        if( TRUE){
            $this->validationRules[] = array('first_name','required');
            $this->validationRules[] = array('last_name','required');
        }

    }

    public $validationRules = array(
        array('email', 'required'),
        array('email, email1, email2, email3', 'email', 'message'=>'Email format is invalid'),
        array('email, address, email1, email2, email3', 'length', 'max'=>255),

    );

    public function rules()
    {
        return $this->validationRules;
    }
}

0
在您的 ActiveRecord 中,您可以在任何地方添加动态验证器。例如,我重写了父类方法 setAttributes,并根据 $this->type 属性中选择的值添加 $this->validatorList->add() 。官方文档:https://www.yiiframework.com/doc/api/1.1/CValidator
public function setAttributes($values, $safeOnly = true)
{
    $result = parent::setAttributes($values, $safeOnly);

    if (self::TYPE_PHONE == $this->type) {
        $this->validatorList->add(CValidator::createValidator('required', $this, ['phone', 'phonePrefix']));
    } elseif (self::TYPE_EMAIL == $this->type) {
        $this->validatorList->add(CValidator::createValidator('required', $this, ['email']));
    }

    return $result;
}

能否请您在回答中添加更多的上下文信息。仅有代码的答案很难理解。如果您能在帖子中添加更多信息,将有助于提问者和未来的读者。 - Collin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接