Activerecord Yii2活动记录模型未保存数据

Activerecord Yii2活动记录模型未保存数据,activerecord,yii2,Activerecord,Yii2,我构建了一个简单的表单模型&视图、一个简单的AR模型和一个简单的控制器。表单模型为AR实例指定了正确的值,但是当我调用save()时,这些值都不会保存在DB中。有什么想法吗 表格模型: <?php namespace app\models; use Yii; use yii\base\Model; class PromptForm extends Model { public $name; public $intro; public $prompt;

我构建了一个简单的表单模型&视图、一个简单的AR模型和一个简单的控制器。表单模型为AR实例指定了正确的值,但是当我调用save()时,这些值都不会保存在DB中。有什么想法吗

表格模型:

<?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;
    }
}
试试看


在控制器中,按如下方式更改if条件:

if ($prompt = $model->post() !== null) {
这将验证返回的值是否为空。

您当前的验证条件只是验证是否将值分配给变量$prompt。这就是为什么它总是返回真的。

好吧,我知道了。事实证明,如果在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';
    }
}
使用


如果这样做有效,则意味着某些验证规则失败

最近,当我将Active Record类与Model类相结合时,遇到了相同的问题。因为我知道AR实际上扩展了Yii2中的模型。为什么不写更少的代码呢?所以我把代码从模型移到AR

$model = new User();  
$model->load(Yii::$app->request->post())
但是AR的_属性没有得到表单中的post数据。表单数据实际上位于模型对象中

object(app\models\User)#39(12){[“password”]=>string(6)“google” [“newpass”]=>NULL[“name”]=>string(5)“Jane1”[“email”]=>string(16) "jane@outlook.com“[”\u属性“:“yii\db\BaseActiveRecord”:private]=> 数组(2){[“密码\u哈希”]=>字符串(60) “$2y$13$.vNKpmosLjW/Oyahiezoj8Rig6QJVQJ8TGHN2x78.75poXVn6Yi” [“auth_key”]=>string(32)“4XggNakVd-oeU28ny7obdw7gOmZJ-Rbu”}


只需删除要批量分配给AR实例的公共属性即可使其正常工作。

对于解决此问题的人,我会记得在保存之前检查
方法(如果存在)。我错误地注释了
return
语句

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

如何排除故障

在开发
\u form.php
时,首先要添加的是errorSummary():

在控制器中:

<?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,
        ]);
    }
}
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]);
}
行为

或者,您可以使用以下行为,而不是在模型中直接分配用户:


很抱歉,$model没有扩展活动记录,因此没有save()方法。$model是我提示的表单模型。它的post()方法调用save()在AR模型上,但由于某些原因,该保存无法正常工作。它返回true,因为已正确创建提示对象,并且在数据库中创建了数据行。唯一的问题是,该数据行仅包含默认数据,没有我尝试向其提供的任何值。提示对象创建正确,但它创建在错误的位置。有没有您可以用一个等号(=)检查任何条件?任何带有=符号的条件都将始终返回true。在这种情况下,该条件将形成类似
$prompt=null
的形式,或者形成类似
$prompt=
,任何方式都将返回true。并且您还告诉我们您没有输入值,那么这是为了什么?`$prompt=new prompt()$prompt->name=$this->name;$prompt->intro=$this->intro;$prompt->prompt=$this->prompt;`您正在为它的属性赋值。我刚刚遇到了同样的问题,让我挠头了一段时间!嗨@Tal V。请勾选它作为正确答案,因为它看起来像是一个未回答的问题。对我也很有用。谢谢sThanks。由于Craft CMS,目前被迫使用Yii。无法说明框架。有太多隐藏的陷阱。极度缺乏例外。整个“不做什么”部分在我看来完全不正确。为表单创建单独的模型更具可读性,更严格地遵守SRP,应该是首选(除非你有真正简单的CRUD).从模型中访问
Yii::$app->user->identity->username
是反模式的-虽然它很简单,适用于多种情况,但这不是正确的做法-模型不应该以这种方式运行。@rob006我愿意修改,但让我们讨论一下,以得出最佳答案。似乎没有必要构建已经发布的代码它位于ActiveRecord类中,即加载、验证和保存。通常,这是在控制器中用yii在一行中完成的:
if($model->load(yii:$app->request->post())和&$model->save()){return$this->redirect(['view',id'=>$model->product_id_pk])
那么,添加扩展类如何比使用模型场景更好呢?另外,我了解您对反模式的看法,分离模型如何解决这个问题?分离模型允许您关注特定的上下文-对于这个特定的表单,您有更小更简单的模型,并且您的主AR模型也更简单,因为它不是这一点在大型应用程序中非常重要,因为AR模型很容易变得臃肿和难以维护。从AR中删除表单处理是使其更简单和更易于维护的步骤之一。在某些情况下,您可以忽略它并在AR模型中处理表单,但创建单独的模型是我们的选择更好的方法(尽管它需要更多的代码)。实际上,您可以在指南的最佳实践中了解它(尽管他们建议通过继承来解决这个问题,这比单独的模型更不干净):我看不出为什么不应该以这种方式分配它。除了模型不应该访问
Yii::$app->user->getId()
直接-它应该从控制器传递到表单模型。
$model = new User();  
$model->load(Yii::$app->request->post())
public function beforeSave($insert)
{
    // never toggle comment on this!!!
    return parent::beforeSave( $insert); 
}
<?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]);
}
/**
 * {@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
        ],
    ];
}