In Yii, is there a way to validate table input with CActiveForm?

Situation

I used the wiki article on the Yii website, Collecting Table Entries , to follow suit.

I do not believe that I need to check table input in the traditional sense for multiple models. I have only one model, but I am dynamically creating the number of fields in the form. Here is a bit more background.

I import CSV files, where their headers differ in order among different files. Before properly disassembling the files, the user needs to match which title will be displayed in which table / column.

I have one model, ImportParseForm extended from CFormModel . This really has only one rule:

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

Here is a snippet of my view:

 <?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; ?> 

Here is a snippet of my controller:

  $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 } } 

If all fields are valid, it passes as expected. The problem is that if one of the fields is invalid (or empty in this case), then all fields are marked as invalid.

In Yii 1.1.10, they added CActiveForm :: validateTabular () , but this seems like a few models. Not quite what I have here. But for the punches, I added the following to my controller (of course, removed another type of check):

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

The form itself is valid only when filling out the first element. If the first element is full, it will set all other elements with the same value (and passes the check).

Question

Basically, can I use CActiveForm to validate the generated dynamic fields (similar to table input, but with only one model)?

+4
source share
2 answers

After reading, the collection of table input is a little closer, I use "several" models. I misunderstood that several models will mean several different structured models, and not just a multiple of the same structured model in an array. For example, in the wiki there is a fragment that shows which elements (an array of models) are updated: $items=$this->getItemsToUpdate(); . My corrected assumption is that this particular method captures a somewhat identical structured model, but with different primary keys ... or different records. Understanding this, the rest of the article makes more sense;)

But here is my model decision on how to create a CSV header display form.

 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); } } 

Here is a fragment of my controller on which my equivalent is $items=$this->getItemsToUpdate(); (again, the goal is to collect an array of models) will look like

  // Get the first row of CSV, assume it 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')); } } 

Push $mForm to your view. Now, in your opinion, iterating through $mForm for your form like this (similar to the wiki article, but I use the CActiveForm widget here):

 <?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; ?> 

Validation works as expected.

If you want to use AJAX validation, use CActiveForm::validateTabular() in your controller (instead of the usual validate() ).

Hope this helps other Yii beginners! :)

0
source

I tried to do this, and this is my decision in the case of a model update form. Here I used a model check for the attributes of the update model in a value change event that does not need a submit button and looks simple and bizarre. Here is a snippet of code ...

view code:

  <?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; ?> 

controller code:

  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(); 
0
source

Source: https://habr.com/ru/post/1399910/


All Articles