Übersetzungen dieser Seite:
  • de

Back to Yii2 Overview

Dynamic Form

In this article we are going to create a dynamic form. It is a form that keeps its structure and rules in configuration arrays, not in hard-coded classes.

We are going to use the DynamicModel.

From the Yii documentation:

DynamicModel is a model class primarily used to support ad hoc data validation.

The Dynamic Model Class

  • Create the Dynamic Model class. Create the file app/models/DynamicModel.php:
<?php
namespace app\models;
 
use \yii\base\DynamicModel;
 
class MyDynamicModel extends DynamicModel
{
    public $attributeLabels = [];
 
    public function attributeLabels(){   
        return $this->attributeLabels;
    }
    public function setAttributeLabel($attribute, $label)
    {
        $this->attributeLabels[$attribute] = $label;
    }
}

The Controller Action

In a controller file (e.g. controllers/SiteController.php), create an action method.\ First, we are creating the _field_ definitions, then the _field rules_:

<?php
use app\models\MyDynamicModel;
 
    public function actionShowForm()
    {
        $fields = [ // {{{ field definitions
            'name'=>[
                'type'=>'text',
                'label'=>'Name',
                'hint' => 'Bitte geben Sie Ihren Familiennamen ein',
            ],
            'vorname'=>[
                'type'=>'text',
                'label'=>'Vorname',
            ],
            'geburtsname'=>[
                'type'=>'text',
                'label'=>'Geburtsname',
            ],
            'strasse'=>[
                'type'=>'text',
                'label'=>'Strasse',
            ],
            'email'=>[
                'type'=>'text',
                'label'=>'E-Mail',
            ],
            'verheiratet' => [
                'type'=>'checkbox',
                'label' => 'Verheiratet',
            ],
            'mypassword'=>[
                'type'=>'password',
                'label'=>'Password',
            ],
            'sex'=>[
                'type'=>'radioList',
                'label'=>'Geschlecht',
                'options'=>['m'=>'männlich', 'f'=>'weiblich'],
                'inline'=>true,
            ],
            'testDropdown' => [
                'type'=>'dropdownList',
                // 'label'=>'Geschlecht',
                'options'=>[1=>'eins', 2=>'zwei'],
            ],
        ]; // }}} 
        $fieldRules = [ // {{{ field rules
            [['name', 'vorname', 'strasse', 'email'], 'required'],
            [['name', 'email'], 'string', 'max'=>128],
            ['email', 'email'],
            [['verheiratet'], 'boolean'],
            [['Geburtsname', 'sex'], 'safe'],
            ['testDropdown', 'number', 'integerOnly'=>true],
        ]; // }}}
 
    }

The $fields array is an array of field attributes, indexed by the field names. As type, we have:

  • text
  • textarea
  • checkbox
  • password
  • dropdownList
  • radioList

The fieldRules array is defined as described in the Guide: Getting Data from Users/Validating Input/Declaring Rules.

We the are going to initialize the model, the checkboxes and the labels:

        $model = new MyDynamicModel(array_keys($fields));
 
        // Init checkbox attributes
        $checkboxes = array();
        // {{{ Init labels
        foreach($fields as $field=>$settings) {
            if(!empty($settings['label']))
                $model->setAttributeLabel($field, $settings['label']);
            else
                $model->setAttributeLabel($field, \yii\helpers\Inflector::camel2words($field, true));
 
            if($settings['type']=='checkbox')   
                $checkboxes[] = $field;
        } // }}} 

We also add the rules we defined earlier, and we initialize some default values for the model attributes:

        // {{{ Add rules to DynamicModel
        foreach($fieldRules as $settings) {
            $attributes = array_shift($settings);
            $validator = array_shift($settings);
            $model->addRule($attributes, $validator, $settings);
        } // }}} 
        // Init default values
        $model->attributes = array( // {{{ 
            'name'          => 'Werner',
            'vorname'       => 'Joachim',
            'strasse'       => 'Am Wingert 10',
            'verheiratet'   => true,
            'sex'           => 'm',
        ); // }}} 

Finally, we render the form:

        return $this->render('form', [
            'model' => $model,
            'fields' => $fields,
        ]);

The Form View

Create the form view file in views/site/form.php:

<?php
use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\web\View;
?>
 
<div class="site-form">
<h1><?= Html::encode($this->title) ?></h1>
 
<?php $form = ActiveForm::begin([
    'id' => 'my-form',
    'layout' => 'horizontal',
    // 'options' => ['class' => 'form-horizontal'],
]); ?>
 
<?= $form->errorSummary($model) ?>
 
<?php 
$yesNoOptions = [1=>'Ja', 0=>'Nein'];
foreach($model->attributes() as $field) 
{
    $input = null;
    switch($fields[$field]['type']) {
        case 'text':
            $input = $form->field($model, $field)->textInput();
            break;
        case 'textarea':
            $textareaOptions = isset($fields[$field]['options']) ? $fields[$field]['options'] : array(); // $yesNoOptions;
            $input = $form->field($model, $field)->textarea($textareaOptions);
            break;
        case 'checkbox':
            $input = $form->field($model, $field)->checkbox();
            break;
        case 'password':
            $input = $form->field($model, $field)->passwordInput();
            break;
        case 'dropdownList':
            $dropdownOptions = isset($fields[$field]['options']) ? $fields[$field]['options'] : array(); // $yesNoOptions;
            $input = $form->field($model, $field)->dropdownList($dropdownOptions);
            break;
        case 'radioList':
            $dropdownOptions = isset($fields[$field]['options']) ? $fields[$field]['options'] : $yesNoOptions;
 
            $input = $form->field($model, $field);
            if(!empty($fields[$field]['inline']) and $fields[$field]['inline']==true)
                $input->inline(true);
            $input->radioList($dropdownOptions);
            break;
        default:
            $input = $form->field($model, $field)->textInput();
            break;
    }
    if(!empty($fields[$field]['hint']))
        $input->hint($fields[$field]['hint']);
 
    echo $input;
}
?>
 
    <div class="form-group">
        <div class="col-lg-offset-1 col-lg-11">
            <?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
        </div>
    </div>
<?php ActiveForm::end() ?>
</div>

This view creates the ActiveForm. In a big switch case block, the various form input controls are created.

Validate the User Input

In the controller file, add this code before the render call:

        // {{{ Evaluate posted data
        if ($model->load(Yii::$app->request->post())  && $model->validate()) {
            Yii::$app->session->setFlash('success', 'The form has been submitted.');
        }