Yii2 通过传递新旧记录并比较数据来创建审计记录

Posted

技术标签:

【中文标题】Yii2 通过传递新旧记录并比较数据来创建审计记录【英文标题】:Yii2 create audit record by passing old and newly updated record and comparing the data 【发布时间】:2016-10-21 08:43:45 【问题描述】:

我正在尝试创建一个可以与其他模型一起使用的create audit 方法。我使用的逻辑是在 submit 从表单和 save() 出现之前传递旧记录。并在“save()”之后传递新更新的数据。我在“发布”请求之前检查了contentBefore 数据,我得到了旧记录。但是在 'save()' contentBefore 数据使用新更新的数据进行更新之后,这显然不是我想要的。

有人可以提出更好的方法或在我的代码中找到错误吗?

谢谢!

这是模型更新动作的代码

public function actionUpdate($id)

    $model = $this->findModel($id);

    // get the old data before update
    $contentBefore = $model;
    // If I var_dump('contentBefore') here I get the old data

    if ($model->load(Yii::$app->request->post()) &&  $model->save()) 

        // get the newly updated data and pass it to 'createaudit'
        $contentAfter = $model;
        $tableName = $model->formName();
        $operation = Yii::$app->controller->action->id;

        // Here var_dump($contentBefore) I get the newly updated data 
        AuditTrialController::Createaudit($contentBefore, $contentAfter, $tableName, $operation);

        return $this->redirect(['view', 'id' => $model->id]);
     else 
        return $this->render('update', [
            'model' => $model,
        ]);
    

我在 AuditTrialController 中创建审核代码

public static function Createaudit($contentBefore, $contentAfter, $tableName, $operation)


    $model = new AuditTrial();

    $model->old = '';
    $model->new = '';

    foreach($contentBefore as $name => $value)
        $tempOne = $name .': '. $value.',  ';
        $before[] = $tempOne;
     

    foreach($contentAfter as $name => $value)
        $tempTwo = $name .': '. $value.',  ';
        $after[] = $tempTwo;
     

    $length = count($after);
    for($x = 0; $x < $length; $x++) 
        if ( $before[$x] != $after[$x] ) 
           $model->old = $model->old.' '.$before[$x];
           $model->new = $model->new.' '.$after[$x];
       
     

    $model->modified_by = Yii::$app->user->identity->username;
    $model->operation = $operation;
    $model->date = date('Y-m-d h:i:s a');
    $model->table_name = $tableName;
    $model->save();

【问题讨论】:

【参考方案1】:

你应该先阅读这篇关于 php Objects and references 的文章:

从 PHP5 开始,对象变量不再包含对象本身作为值。它只包含一个对象标识符,允许对象访问者找到实际对象。

这只是意味着$contentBefore$contentAfter 是相同的...

一个简单的解决方法是使用$attributes,例如:

$model = $this->findModel($id);
$oldAttributes = $model->attributes;
if ($model->load(Yii::$app->request->post()) &&  $model->save()) 
    $newAttributes = $model->attributes;
    $tableName = $model->formName();
    $operation = Yii::$app->controller->action->id;
    AuditTrialController::Createaudit($oldAttributes, $newAttributes, $tableName, $operation);
    return $this->redirect(['view', 'id' => $model->id]);

另一种解决方案是使用Dirty Attributes(但新旧值的比较将使用===)。

【讨论】:

【参考方案2】:

我已经解决了我的问题。感谢 Soju 指出我的错误。我通过活动记录获得$contentBefore$contentAfter 值。这对我有用。如果我需要改进我的代码,请告诉我。

public function actionUpdate($id)
    $model = $this->findModel($id);

    // get the old data before update 
    $modelname = get_class($model); // updated part
    $contentBefore = $modelname::findOne($id); // updated part

    if ($model->load(Yii::$app->request->post()) &&  $model->save()) 

        // get the newly updated data and pass it to 'createaudit'
       $contentAfter = $modelname::findOne($id); // updated part
       $tableName = $model->formName();
       $operation = Yii::$app->controller->action->id;

       AuditTrialController::Createaudit($contentBefore, $contentAfter, $tableName, $operation);

       return $this->redirect(['view', 'id' => $model->id]);
     else 
        return $this->render('update', [
            'model' => $model,
        ]);   
    

 

【讨论】:

是的,您确实需要更好的代码...您尝试过我的吗? 你是说使用dirty attributes吗?

以上是关于Yii2 通过传递新旧记录并比较数据来创建审计记录的主要内容,如果未能解决你的问题,请参考以下文章

oracle如何启用审计

Yii2数据库分页操作方法介绍

Yii2 - 仅当记录是新的时才使用默认值

Yii2之组件的注册与创建

在 Rails 中审计记录

LINUX服务器--所有用户登陆操作命令审计