Модель активной записи Yii2 не сохраняет данные

Я построил простую модель модели и представление, простую модель AR и простой контроллер. Модель формы присваивает правильные значения экземпляру AR, но когда я вызываю save(), ни одно из этих значений не сохраняется в БД. Любые идеи?

Модель формы:

<?php

namespace app\models;

use Yii;
use yii\base\Model;

class PromptForm extends Model
{
    public $name;
    public $intro;
    public $prompt;
    public $notes;
    public $questions;


    public function attributeLabels()
    {
        return [
            'name' => 'Prompt title',
            'intro' => 'Intro',
            'prompt' => 'Prompt body',
            'notes' => 'Closing notes',
            'questions' => 'Exploration questions',
        ];
    }

    /**
     * @return array the validation rules.
     */
    public function rules()
    {
        return [
            [['name', 'prompt'], 'required'],
            ['name', 'filter', 'filter' => 'trim'],
            ['name', 'string', 'max' => 255],
            [['intro', 'prompt', 'notes', 'questions'], 'default'],
        ];
    }

    public function post()
    {
        if ($this->validate()) {
            $prompt = new Prompt();
            $prompt->name = $this->name;
            $prompt->intro = $this->intro;
            $prompt->prompt = $this->prompt;
            $prompt->notes = $this->notes;
            $prompt->questions = $this->questions;

            $prompt->author = \Yii::$app->user->getId();

            //die(print_r($prompt, TRUE));

            $prompt->save();

            return $prompt;
        }

        return null;
    }
}

Модель AR:

<?php

namespace app\models;

use Yii;
use yii\db\ActiveRecord;

/**
 * Prompt is the model behind the prompt item.
 */
class Prompt extends ActiveRecord
{
    public $name;
    public $intro;
    public $prompt;
    public $notes;
    public $questions;
    public $status;
    public $author;

    public $id;

    /**
     * @return string the name of the table associated with this ActiveRecord class.
     */
    public static function tableName()
    {
        return 'prompt';
    }

    /**
     * @return array the attribute labels.
     */
    public function attributeLabels()
    {
        return [
            'name' => 'Prompt title',
            'intro' => 'Intro',
            'prompt' => 'Prompt body',
            'notes' => 'Closing notes',
            'questions' => 'Exploration questions',
            'status' => 'Status',
            'author' => 'Author ID',
        ];
    }
}

Контроллер:

<?php

namespace app\controllers;

use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\filters\VerbFilter;
use app\models\PromptForm;
use app\models\Prompt;

class PromptsController extends Controller
{
    public function actionIndex()
    {
        // Return a list of all prompts:
        return $this->render('index');
    }

    public function actionNew()
    {
        if (\Yii::$app->user->isGuest) {
            return $this->goHome();
        }

        $model = new PromptForm();
        if ($model->load(Yii::$app->request->post())) {
            if ($prompt = $model->post()) {
                Yii::$app->getSession()->setFlash('success', 'Your prompt was created successfully!');
                return $this->goHome();
            } else {
                Yii::$app->getSession()->setFlash('error', 'Error while submitting your prompt.');
            }
        }

        return $this->render('create', [
            'model' => $model,
        ]);
    }
}

Ответ 1

Хорошо, я понял это. Оказывается, что если вы объявляете публичные атрибуты в своей модели ActiveRecord, они скрывают автоматические атрибуты, созданные AR. Данные присваиваются вашим скрытым атрибутам, но не отправляются в базу данных.

Правильная модель AR должна была быть просто следующей:

<?php

namespace app\models;

use Yii;
use yii\db\ActiveRecord;

class Prompt extends ActiveRecord
{
    /**
     * @return string the name of the table associated with this ActiveRecord class.
     */
    public static function tableName()
    {
        return 'prompt';
    }
}

Ответ 2

Попробуйте

    if ($model->load(Yii::$app->request->post())) {
                if ($prompt = $model->post()) {
                    $model->save()
                    Yii::$app->getSession()->setFlash('success', 'Your prompt was created successfully!');
                    return $this->goHome();
                } else {
                    Yii::$app->getSession()->setFlash('error', 'Error while submitting your prompt.');
                }
            }

Ответ 3

Используйте

$prompt->save(false);

Если это работает, это означает, что какое-то правило проверки не срабатывает.

Ответ 4

В контроллере измените условие if следующим образом:

if ($prompt = $model->post() !== null) {

Это подтвердит, что значение, которое является возвратом, не является нулевым.
Ваше текущее условие проверки только подтверждает, где значение присваивается переменной $prompt или нет. И поэтому он всегда возвращает true.

Ответ 5

Я столкнулся с той же проблемой в последнее время, когда я совмещаю класс Active Record с классом Model. Потому что я знаю, что AR фактически расширяет модель в Yii2. Почему бы не написать меньше кода. Поэтому я перемещаю код из модели в AR.

$model = new User();  
$model->load(Yii::$app->request->post())

Но атрибут AR _ не получил данные сообщения в форме. данные формы фактически находятся в объекте Model.

object (app\models\User) # 39 (12) {[ "password" ] = > string (6) "google" [ "newpass" ] = > NULL [ "name" ] = > string (5) "Jane1" [ "email" ] = > string (16) "[email protected]" [ "_attributes": "yii\db\BaseActiveRecord": private] = > array (2) {[ "password_hash" ] = > string (60) "$ 2y $13 $.vNKpmosLjW/oYAhIezOZOj8rIG6QJvQj8tGHN2x78.75poXVn6Yi" [ "auth_key" ] = > строка (32) "4XggNakVd-oeU28ny7obdw7gOmZJ-Rbu" }

просто удалите общедоступный атрибут, который вы хотите присвоить массовому назначению экземпляру AR, чтобы он работал.

Ответ 6

Для тех, кто борется с этой проблемой, я не забудьте проверить метод beforeSave, если таковой имеется. Я по ошибке закомментировал return выражение.

public function beforeSave($insert)
{
    // never toggle comment on this!!!
    return parent::beforeSave( $insert); 
}

Ответ 7

Как устранить неполадки

Первое, что вы должны добавить при разработке вашего _form.php это errorSummary():

<?php $form = ActiveForm::begin(); ?>
// Some input fields
...
<?= $form->errorSummary($model); ?> // <--- Add this 
...
<?php ActiveForm::end(); ?> 

упрощать

Почему бы не использовать сценарии вместо этого, если есть некоторая форма минимальной вариации для формы:

В вашей модели:

    public function rules()
    {
        return [
            [['field_1'], 'required', 'on' => self::SCENARIO_ADD],  // only on add
            [['field_2'], 'required', 'on' => self::SCENARIO_UPDATE], // only on update
            [['field_3', 'field_4'], 'required'], // required all the time
        ];
    }

В вашем контроллере:

public function actionAdd()
{
    $model = new Model();
    $model->scenario = Model::SCENARIO_ADD;
    if ($model->load(Yii::$app->request->post())) {
        return $this->redirect(['view', 'id' => $model->id]);
    }

    return $this->render('add', ['model' => $model]);
}

поведения

В качестве альтернативы, вместо того, чтобы назначать пользователя непосредственно в вашей модели, вы можете использовать такое поведение:

https://www.yiiframework.com/doc/api/2.0/yii-behaviors-blameablebehavior

/**
 * {@inheritdoc}
 */
public function behaviors()
{
    return [
        [
            'class' => \yii\behaviors\BlameableBehavior::className(),
            'value' => Yii::$app->user->identity->username,
        ],
        [
            'class' => \yii\behaviors\TimestampBehavior::className(),
            'value' => new \yii\db\Expression('NOW()'),
        ],
        [
            'class' => 'sammaye\audittrail\LoggableBehavior',
            'userAttribute' => 'updated_by', //blameable attribute of the current model.
            'ignored' => ['updated_by', 'updated_at'], // This ignores fields from a selection of all fields, not needed with allowed
        ],
    ];
}