使用Active Record,如何通过其父级保存孩子的详细信息?

时间:2015-07-07 17:33:57

标签: activerecord yii2

我在Yii2 Active Record中使用parent-> child(master-> detail)关系

当我想创建一个孩子时,我必须手动填写其父信息,如下所示:

  

关系:客户(1)---> (n)评论

class ClientController extends \yii\web\Controller
{

    public function actionAddComment() {
        $comment = new Comment;
        if ($comment->load(Yii::$app->request->post())) {
            $comment->client = $this->id;  // Client id
            $comment->save();
        }
        return $this->render('view', ['comment'=>$comment]);

    }
}

我已经对它进行了优化,创建了一个Comment方法来执行此操作:

class Comment extends ActiveRecord {

    public function newComment($client) {
        $comment = new Comment;
        $comment->client = $client;  // Client id
        return $comment;
    }
}

我在评论模型中经历过之前保存,但仍然不确定是否有更好的方法。

是否有类似的内容:

$comment = new Comment(Yii::$app->request->post());
$client->save($comment);  // Here the parent is writing his information to the child

或单行快捷方式:

$client->save(new Comment(Yii::$app->request->post());

无需在beforeSave中创建此逻辑?

1 个答案:

答案 0 :(得分:1)

是的,我建议使用Active Record提供的内置link()unlink()方法,您可以在控制器中使用它们来关联或取消两个模式,它们共享多对多或一对多的关系。

如果使用link( $name, $model, $extraColumns = [] )

,它甚至还有一个可选的$ extraColumns属性,用于将其他列值保存到联结表中

所以你的代码可能如下所示:

$comment = new Comment;
if ($comment->load(Yii::$app->request->post())) {
    $comment->link('client', $this);
}

查看docs了解详情。

现在关于在何处使用此代码来关联模型,它取决于您的应用程序的结构。我不确定通过触发事件做这件事是不是一个好习惯,你需要记住错误可能会发生 在抛出异常之前,您可能需要评估某些场景或逻辑。所以在我的情况下,我更喜欢将该代码用于我的控制器。

有时您需要像actionAddComment()那样构建一个特定的操作,在某些其他情况下,例如当您的Post请求更新Parent模型并同时更新其相关的子模型时,Parent的更新操作ClientController::actionUpdate()可能是一个很好的地方,也许这样的事情会起作用:

$params = Yii::$app->request->post();

$client->load($this->params, '');
if ($client->save() === false && !$client->hasErrors()) {
    throw new ServerErrorHttpException('Failed to update the object for unknown reason.');
}

foreach ($params["comments"] as $comment) {
  // We may be sure that both models exists before linking them.
  // In this case I'm retrieving the child model from db so I don't
  // have to validate it while i just need its id from the Post Request
  $comment = Comment::findOne($comment['id']);
  if (!$comment) throw new ServerErrorHttpException('Failed to update due to unknown related objects.');
  // according to its documentation, link() method will throw an exception if unable to link the two models.
  $comment->link('client', $client);     
  ...