Как установить правила проверки для пользовательских атрибутов CActiveRecord в Yii?

Я работаю над проектом Yii с базой данных, которая содержит таблицу, в которой почти все его данные сохраняются в поле как JSON (это безумие, но так оно и есть):

id      INTEGER
user_id INTEGER
data    LONGTEXT

Это "поле JSON" data имеет следующую структуру и содержит, среди прочего, изображение:

{
   "id":"1",
   "foo":"bar",
   ...
   "data":{
      "baz":"buz",
      ...
    }
}

Отображать это не проблема, но теперь я хочу сделать данные редактируемыми. Моя форма выглядит так:

<?php
$form = $this->beginWidget('CActiveForm', array(
    'id' => 'my-form',
    'htmlOptions' => array('enctype' => 'multipart/form-data'),
    'enableAjaxValidation'=>false,
));
?>
<div class="row">
    <?php echo $form->labelEx($model, 'foo'); ?>
    <?php
    echo $form->textField($model, 'foo', array(...));
    ?>
    <?php echo $form->error($model, 'foo'); ?>
</div>
<div class="row">
    <?php echo $form->labelEx($model, 'baz'); ?>
    <?php
    echo $form->textField($model, 'data[baz]', array(...));
    ?>
    <?php echo $form->error($model, 'data[baz]'); ?>
</div>

Оно работает. Но есть много проблем, которые, кажется, вызваны одной и той же вещью - то, что поля формы не связаны с атрибутами / свойствами модели:

  1. Когда я делаю поля foo а также baz требуется (public function rules() { return array(array('foo, baz', 'required')); } -- недвижимость $foo определено) foo бахает как хотел, но baz вызывает ошибку "foo не может быть пустым". Поэтому я не могу установить data[*] как required,

  2. Если форма недействительна и перезагружается, все data[*] поля пусты

  3. data[*] поля не помечены как обязательные.

Есть ли, чтобы решить эту проблему без изменения структуры данных? Там не будет правильного пути для этого, но, возможно, обходной путь.

1 ответ

Невозможно проверить поля таким способом. Прежде всего, если вы используете поле в модели, оно должно быть определено или существовать в таблице для активной записи. Поэтому, если вы хотите проверить такую ​​структуру, единственный верный способ сделать это:

class Model extends CActiveRecord {
  // Define public varialble
  public $data_baz;

  public function rules(){
    return array(
      // Add it to rules
      array( 'data_baz', 'required' )
    );
  }

  public function attributeLabels(){
    return array(
      // Add it to list of labels
      'data_baz' => 'Some field'
    );
  }

  protected function beforeSave(){
    if ( !parent::beforeSave() ) {
      return false;
    }

    // Also you may create a list with names to automate append
    $this->data['baz'] = $this->data_baz;

    // And serialize data before save
    $this->data = serialize( $this->data );

    return true;
  }
}

И ваша форма должна выглядеть так

<div class="row">
    <?php echo $form->labelEx($model, 'data_baz'); ?>
    <?php echo $form->textField($model, 'data_baz'); ?>
    <?php echo $form->error($model, 'data_baz'); ?>
</div>
Другие вопросы по тегам