在Yii中,有没有办法用CActiveForm验证表格输入?

时间:2012-03-06 01:45:57

标签: php yii

情况

我在Yii的网站Collecting Tabular Input上使用了wiki文章作为例子。

我不相信我需要在传统意义上针对多个模型验证表格输入。我只有一个模型,但我正在动态创建表单中的字段数。这里有更多背景知识。

我正在导入CSV文件,其标题在不同文件中按顺序变化。在正确解析文件之前,用户需要映射哪个标头将映射到哪个表/列。

我有一个模型,ImportParseFormCFormModel扩展而来。它实际上只有一条规则:

public function rules()
{
    return array(
        array('header', 'required'),
    );
}

以下是我的观点片段:

<?php foreach($headers as $h => $hItem): ?>    
<div class="row">
    <?php echo CHtml::label(CHtml::encode($hItem), "[$h]header"); ?> maps to
    <?php echo $fParse->textField($mForm, "[$h]header"); ?>
    <?php echo $fParse->error($mForm, "[$h]header"); ?>
</div>
<?php endforeach; ?>

这是我的控制器片段:

        $mForm = new ImportParseForm;
        $valid = true;

        if (isset($_POST['ImportParseForm'])){
            foreach ($headers as $h => $hVal){
                if (isset($_POST['ImportParseForm'][$h])){
                    $mForm->attributes = $_POST['ImportParseForm'][$h];
                    $valid = $mForm->validate() && $valid;
                }
            }


            if ($valid){
                // Process CSV
            }
        }

如果所有字段都有效,则按预期传递。问题是如果其中一个字段无效(或者在这种情况下为空),那么所有字段都会被标记为无效。

在Yii 1.1.10中,他们添加了CActiveForm::validateTabular(),但看起来它适用于多个模型。不是我在这里的东西。但是对于踢,我将以下内容添加到我的控制器中(当然,删除了其他类型的验证):

CActiveForm::validateTabular($mForm, array('header'));

表单本身仅在填充第一个元素时有效。如果填充了第一个元素,它将使用相同的值设置所有其他元素(并通过验证)。

问题

基本上,我可以使用CActiveForm对动态生成的字段进行验证(类似于表格输入,但只有一个模型)?

2 个答案:

答案 0 :(得分:1)

我试图做类似的事情,这是我的模型更新表格的解决方案。在这里,我利用了值更改事件的更新模型属性的模型验证,它不需要提交按钮,看起来简单而且花哨。这是代码片段......

查看代码:

    <?php foreach($modelArray as $model): ?>
        <div class="row">
                <?php echo $form->textField($model, "[$model->id]attributeName"); ?>
                <?php echo $form->label($model, "[$model->id]attributeName"); ?>
                <?php echo $form->error($model, "[$model->id]attributeName"); ?>
        </div>
    <?php endforeach; ?>

控制器代码:

    objArray = array();
    foreach($_REQUEST['ModelName'] as $id => $attributes){
        $obj = ModelName::model()->findByPk($id);
        $obj->attributes = $attributes;
        $obj->save();
        $objArray[$id] = $obj;
    }
    echo CActiveForm::ValidateTabular($objArray);
    Yii::app()->end(); 

答案 1 :(得分:0)

在阅读Collecting Tabular Input之后,我正在使用“多个”模型。我误解了多个模型意味着多个不同的结构化模型,而不仅仅是阵列中相同结构化模型的多个。例如,在wiki中有一个部分显示要更新的项目(模型数组):$items=$this->getItemsToUpdate();。我更正的假设是,该特定方法可以抓取多个相同的结构化模型,但具有不同的主键...或不同的记录。理解这一点,本文的其余部分更有意义;)

但这是关于如何创建CSV标题映射表单的模型解决方案。

class ImportParseForm extends CFormModel{

    // Model really only has one attribute to check against, the header
    var $header;
    // New attributeLabels collected and stored on class instantiation
    protected $attributeLabels;

    // Modify construct so we can pass in custom attribute labels
    public function __construct($attributeLabels = '', $scenario = '')
    {
        if (! is_array($attributeLabels)){
            $this->attributeLabels = array($attributeLabels);
        }
        else{
            $this->attributeLabels = $attributeLabels;
        }

        parent::__construct($scenario);
    }


    public function rules()
    {
        return array(
            array('header', 'required'),
        );
    }

    public function attributeLabels()
    {
        // Default mapping
        $arr = array(
            'header' => 'Header Mapping',
        );

        // Merge mapping where custom labels overwrite default
        return array_merge($arr, $this->attributeLabels);
    }
}

这是我的控制器中的一个代码片段,我的等同于$items=$this->getItemsToUpdate();(再次,目标是收集一系列模型)看起来像

        // Get the first row of CSV, assume it's the headers
        $tmpCsvRow = explode("\n", $mTmp->data);
        $headers = explode(',', $tmpCsvRow[0]);

        foreach ($headers as $header){
            if (! empty($header)){ // Blank headers are lame, skip them
                // Add a new model for each CSV header found into $mForm array
                // You can also add in a custom attributeLabel, $header is an actual header name like 'First Name',
                // so the new label for the header attribute in ImportParseForm would be 'First Name header' and
                // it will show up properly in your CActiveForm view
                $mForm[] = new ImportParseForm(array('header' => $header.' header'));
            }
        }

$mForm推送到您的视图。现在在您的视图中,为您的表单迭代$mForm(类似于wiki文章,但我在这里使用了CActiveForm小部件):

<?php foreach($mForm as $m => $mItem): ?>
<div class="row">
    <?php echo $fParse->labelEx($mItem,"[$m]header"); ?> maps to
    <?php echo $fParse->textField($mItem, "[$m]header"); ?>
    <?php echo $fParse->error($mItem, "[$m]header"); ?>
</div>
<?php endforeach; ?>

验证按预期工作。

如果您想使用AJAX验证,请在控制器中使用CActiveForm::validateTabular()(而不是正常的validate())。

希望这有助于其他Yii初学者! :)