Yii2: The proposal to use the definition labels of attribute for DynamicModel.

Created on 8 Dec 2014  路  10Comments  路  Source: yiisoft/yii2

I use DynamicModel for creating dynamic fields with client validation, therefore i need definition labels of attributes.

Example code:

class DynamicModel extends \yii\base\DynamicModel
{
    private $_attributeLabels;

    public function defineAttribute($name, $value = null)
    {
        $this->_attributes[$name] = $value;
        return $this;
    }

    public function defineLabel($name, $label)
    {
        $this->_attributeLabels[$name] = $label;
    }

    public function attributeLabels()
    {
        return $this->_attributeLabels;
    }
}

Most helpful comment

Instead of using DynamicModel you should create you own model:

class CategoryAttributesModel extends Model
{
    public $category;

    public function attributes()
    {
        $attributes = [];
        foreach ($this->category->attributes as $categoryAttribute) {
            $attributes[] = 'category_' . $categoryAttribute;
        }
        return $attributes;
    }

    public function rules()
    {
        $rules = [];
        foreach ($this->attributes() as $attribute) {
            $rules[] = [$attribute, 'required']
        }
        return $rules;
    }
}

I hope this code can provide you the idea.

All 10 comments

Why do you need this?
Note that DynamicModel has been created to allow execution of the particular validator and does not meant to be used for error message composition.

I know, but DynamicModel is the great class, as it can to use not only as ad-hoc validation, but also as model for creating dynamic fields form against help ajax.

I describe a small example of how I use:

publuc getAdditionalFields() 
{
    /**
     * Bad code, but i need discard echo output in init method of widget.
     * I propose to move code from ActiveForm::init()
     *    echo Html::beginForm($this->action, $this->method, $this->options);
     * to ActiveForm::begin(), so the source code will be more clean and understandable.
     */
    ob_start();
    $form = ActiveForm::begin([
        'layout'      => 'stacked',
        'fieldConfig' => [
            'inputOptions' => ['class' => 'uk-form-large uk-width-1-1']
        ]
    ]);
    ob_end_clean();

    $js = [];
    $html = '';

    $attributeTemplate = new Template();

    /**
     * In function getAttributesByCategoryId sample code:
     *
     *  $model = new DynamicModel();
     *  .....
     *  $model->defineAttribute('attr_' . $attribute_id)
     *        ->defineLabel('attr_' . $attribute_id, $attribute['name']);
     *  .....
     *  $model->addRule('attr_' . $attribute_id, 'integer', ['min' => $attribute['settings']['min'], 'max' => $attribute['settings']['max']]);
     */
    list($model, $attribute_groups) = $attributeTemplate->getAttributesByCategoryId($category_id);

    foreach ($attribute_groups as $attribute_group) {
        foreach ($attribute_group['attributes'] as $attribute) {

            /**
             * I have been changed access function 'getClientOptions' from protected to public access in my subclass.
             * I also propose to change access 'getClientOptions' to access to functions client Validation in custom situation.
             */
            $clientOptions = $form->field($model,  'attr_' . $attribute['attribute_id'])->getClientOptions();

            if (!empty($clientOptions))
                $js['attr_' . $attribute['attribute_id']] = $clientOptions;
        }
    }

    /**
     *  In function 'renderPartial' generating HTML code, for my dynamic fields.
     */
    Yii::$app->response->data['js']   = Json::encode($js);
    Yii::$app->response->data['html'] = $this->renderPartial('attributes', [
        'form'             => $form,
        'model'            => $model,
        'attribute_groups' => $attribute_groups
    ]);
}

Simple code on JS for appending HTML content and eval JS code.

$.getJSON('[]', param, app.ajaxIsSuccess(function(json) {
       var attribute = (new Function("", "var json = " + json.js + "; return json;"))();
       $("#product-features").append(json.html);

        $.each(attribute, function(id, options) {
            $('#product-form').yiiActiveForm('add', options);
       });
});

Sorry for my weak English, but in a way I have been implemented generating dynamically fields with a client validation.

In your example it is better to define a special model class, with your own attributes() method implemntation, instead of using dynamic model for this.

I have classifier which contains about 8000 categories, each category has about 150 attributes. In the future the number of attributes and categories can be changed. I have been created templates for manage categories and its attributes throught web interface. Therefore i need in dynamic model, for me the good solution is DynamicModel, with its dynamic definition attributes and rules.

Your own mode still should be dynamic.
Your need is specific and reqiures specific solution.

Instead of using DynamicModel you should create you own model:

class CategoryAttributesModel extends Model
{
    public $category;

    public function attributes()
    {
        $attributes = [];
        foreach ($this->category->attributes as $categoryAttribute) {
            $attributes[] = 'category_' . $categoryAttribute;
        }
        return $attributes;
    }

    public function rules()
    {
        $rules = [];
        foreach ($this->attributes() as $attribute) {
            $rules[] = [$attribute, 'required']
        }
        return $rules;
    }
}

I hope this code can provide you the idea.

+1 for ability to setting attributeLabels. Sometimes we creates forms with mixed logic. DynamicModel perfect works in frontend with ActiveForm It lacks only the correct validation messages.

+1

+1

+1 use dynamic model is a quicker way to make small model than writing regular model class. My use case is search model with the only attribute 'query' and string length validator. I want to set label for this attribute, but I can't.

Was this page helpful?
0 / 5 - 0 ratings