Нестандартное использование динамической модели

Обсуждение документации второй версии фреймворка. Переводы Cookbook и авторские рецепты.
Ответить
von.hamster
Сообщения: 69
Зарегистрирован: 2013.06.06, 16:07

Нестандартное использование динамической модели

Сообщение von.hamster »

Есть таблица, в которой хранятся настройки системы (настройки при необходимости добавляются). Поля - alias - ключ, по которому свойство достаем, title - название, value - значение (все текстовые).
Задача - вывести все настройки на одной странице для редактирования.
Замечание - на самом деле есть еще 2 поля - group (группа свойств, для группировки настроек на странице, сделал в виде табов) и type - тип поля (строка, текст, чекбокс...), но они сейчас не важны.
Возможно - велосипед, если, кто знает - как это сделать лучше, проще - отпишите.

Нестандартность сводится к тому, что динамическая модель, если я правильно понял, изначально предназначена для валидации.

Опишу основную идею, как решил задачу (сохранение вынес за рамки поста).
1. gii сгенерил crud и модель.
2. Добавил новый класс, наследуемый от yii\base\DynamicModel - нужен для возможности указать метки к полям.

Код: Выделить всё

<?php
namespace app\components\base;
class DynamicModel extends \yii\base\DynamicModel
{
    protected $_labels = [];

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

    public function setAttributeLabels($labels = [])
    {
        $this->_labels = $labels;
    }
}
3. Добавил action:

Код: Выделить всё

    public function actionProfile()
    {
        $options = [];
        $data = [];
        $labels = [];

        /** @var Options[] $optionsRaw */
        $optionsRaw = Options::find()
            ->orderBy(['title' => SORT_ASC])
            ->all();
        
        // Группировка свойств, подготовка данных для динамической модели
        foreach ($optionsRaw as $opt) {
            $options[$opt->group_title][$opt->alias] = $opt;
            $data[$opt->alias] = $opt->text_value;
            $labels[$opt->alias] = $opt->title;
        }
        unset($optionsRaw);

        // создание модели
        $model = new DynamicModel($data);
        $model->setAttributeLabels($labels);

        return $this->render('profile', [
                'options'   => $options,
                'model'     => $model,
        ]);
    }
4. Добавил вьюшку (с псевдо табами, о чем говорил выше):

Код: Выделить всё

<?php
use yii\bootstrap\ActiveForm;
/* @var $this yii\web\View */
/* @var $options array */
/* @var $gOptions \app\modules\admin\models\base\Options[] */
$this->title = 'Настройки';
$this->params['breadcrumbs'][] = $this->title;
?>
<?php $form = ActiveForm::begin() ?>
<div class="options-profile" id="profileOptions">
    <div class="list-group col-lg-3 col-md-4 col-sm-4 col-xs-6">
        <?php foreach ($options as $group => $gOptions) { ?>
            <!-- md5 нужно просто для того, чтобы русские названия перевести в латинские, чтобы не заморачиваться с транслитерацией -->
            <a href="#<?= md5($group)?>" class="list-group-item">
                <?=$group?>
            </a>
        <?php } ?>
    </div>
    <div class="col-lg-9 col-md-8 col-sm-8 col-xs-6">
        <?php foreach ($options as $group => $gOptions) { ?>
            <div class="tab-pane" id="<?=md5($group)?>">
                <?php foreach ($gOptions as $alias => $opt) { ?>
                    <?=$form->field($model, $alias)->textarea()?>
                <?php } ?>
            </div>
        <?php } ?>
    </div>
</div>
<?php  ActiveForm::end(); ?>
<?php $this->registerJs("
    // временная заглушка для табов
    $(function(){
        var p = $('#profileOptions');

        $('.tab-pane', p).hide();

        p.on('click', '.list-group-item', function() {
            $('.tab-pane', p).hide();
            $('.list-group-item', p).removeClass('active');
            $(this).addClass('active');
            $($(this).attr('href')).show();
            return false;
        });

        $('.list-group-item:first', p).trigger('click');
    });
");?>
Ну и в итоге получаем полноценную форму, на которую в последствии повешу еще валидацию (для настроек валидации добавлю поле в таблицу, в которой будет предопределенный набор простых валидаторов, как вариант).
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Нестандартное использование динамической модели

Сообщение zelenin »

как вы правильно сказали, DynamicModel нужна для динамической валидации данных, не сохраняемых в таблицу.
Вам же нужна обыкновенная AR-модель.
von.hamster
Сообщения: 69
Зарегистрирован: 2013.06.06, 16:07

Re: Нестандартное использование динамической модели

Сообщение von.hamster »

Дело в том, что эта модель изначально не предопределена. Неизвестно количество и тип полей. Плюс валидация понадобится. Фактически я собираю модель из нескольких. Как это сделать используя чистый AR - пока не придумал.

Может я не очень понятно описал. Например, в таблице options у меня 2 записи:
"alias1","первый параметр","Значение1"
"alias2","второй параметр","Значение2"

Для формирования формы (activeForm) нужна модель. AR связана с таблицей, точнее с одной записью, а у меня 2.
При помощи динамической модели я формирую модель со свойствами:
$model->alias1 = "Значение1";
$model->alias2 = "Значение2";
При сохранении я разбираю эту модель на составляющие и сохраняю.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Нестандартное использование динамической модели

Сообщение zelenin »

так где вы все это дело валидируете-то? в коде нет, а это самое главное. Т.к. если вы валидируете все по отдельности, тогда все это фейк )
von.hamster
Сообщения: 69
Зарегистрирован: 2013.06.06, 16:07

Re: Нестандартное использование динамической модели

Сообщение von.hamster »

Я отписал, что валидацию добавлю позже. Тип валидатора будет хранится в отдельном поле. Соответственно - сама валидация будет перед сохранением, единоразово. Тоесть массив с правилами будет собираться там-же, где и метки.

По поводу фейка - вопрос: как еще можно организовать форму по указанным выше данным?
Тоесть чтобы поля записи базы были элементами свойств AR или просто компонента модели, которую можно использовать при создании формы?
Или по другому - как создать модель со своими свойствами, которые неизвестны заранее (точнее неизвестно количество, название и метки), не используя DynamicModel?
Аватара пользователя
KiTE
Сообщения: 112
Зарегистрирован: 2012.04.12, 14:47

Re: Нестандартное использование динамической модели

Сообщение KiTE »

Сделайте под эту форму отдельную модель со всем набором опций и правил валидации. Например:

Код: Выделить всё

class OptionsForm extends \yii\base\Model
{
    public function save()
    {
        if ($this->validate()) {
            // Сохраняем
            return true;
        }
        return false;
    }
}
 
Это будет логичнее всего.
Ответить