Я использовал статью wiki на сайте Yii, собирая табличный вход , чтобы следовать примеру.
Я не считаю, что мне нужно проверять табличный ввод в традиционном смысле в отношении нескольких моделей. У меня есть только одна модель, но я динамически создаю количество полей в форме. Вот немного больше фона.
Я импортирую CSV-файлы, где их заголовки различаются по порядку среди разных файлов. Перед правильной разборкой файлов пользователю необходимо сопоставить, какой заголовок будет отображаться в какой таблице / столбце.
У меня есть одна модель, ImportParseForm
расширенная от CFormModel
. У этого действительно есть только одно правило:
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 для проверки правильности генерируемых динамических полей (аналогично табличному вводу, но только с одной моделью)?
После чтения « Сбор табличных входов» немного ближе, я использую «несколько» моделей. Я неправильно понял, что несколько моделей будут означать несколько разных структурированных моделей, а не только кратную одной и той же структурированной модели в массиве. Например, в вики есть часть, которая показывает, какие элементы (массив моделей) обновляется: $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! 🙂
Я пытался сделать подобное, и это мое решение в случае формы обновления модели. Здесь я использовал проверку модели для атрибутов модели обновления в событии изменения стоимости, которому не нужна кнопка отправки, и выглядит просто и причудливо. Вот фрагмент кода …
просмотреть код:
<?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();