Php Laravel pivot表创建关联一次,然后更新

Php Laravel pivot表创建关联一次,然后更新,php,mysql,laravel,eloquent,Php,Mysql,Laravel,Eloquent,我有以下表格: 用户: 教训: lessonID ... 用户\u课程\u状态(充当数据透视表并保存其他信息): 我想做的是,对于每个用户,对于每个课程,pivot表中应该有一行,告诉用户在该课程中完成了多少,以及他们最新的部分ID是什么。也就是说,应该有一对唯一的userID和lessonID(主键?) 我的模型设置如下: <?php class User extends Eloquent implements UserInterface, RemindableInterface {

我有以下表格:

用户:

教训:

lessonID
...
用户\u课程\u状态(充当数据透视表并保存其他信息):

我想做的是,对于每个用户,对于每个课程,pivot表中应该有一行,告诉用户在该课程中完成了多少,以及他们最新的部分ID是什么。也就是说,应该有一对唯一的
userID
lessonID
(主键?)

我的模型设置如下:

<?php

class User extends Eloquent implements UserInterface, RemindableInterface {

...


    public function lessonStatuses() 
    {
        return $this->belongsToMany('Lesson', 'users_lessons_status', 'lessonID', 'userID')->withPivot('latestSectionID', 'percentComplete');
    }

}

<?

class Lesson extends Eloquent {

protected $table = 'lessons';
protected $primaryKey = 'lessonID';

public function userStatuses()
{
    return $this->belongsToMany('User', 'users_lessons_status', 'userID', 'lessonID');
}


}

?>
但是,这是可行的,每次我为相同的
userID
lessonID
更新它时,它都会创建一个新行,因此该对不再是唯一的。为此,我应该使用哪些方法?我在文档中尝试了
save()
attach()
push()
,但我不确定在这里使用哪一个

编辑:为了澄清,生成的表应该如下所示:

id|userID|lessonID|latestSectionID|percentComplete
1    1      1             X             Y
2    1      2        
3    1      3         
4    2      1          
5    3      1
6    3      2
....

edit2:修复了
User->belongtomany()
方法,并添加了
withPivot
调用

这似乎是一个bug,但您可以这样做:

...->sync([$id], false); // detaching set to false, so it will only insert new rows, skip existing and won't detach anything
编辑: 正如在评论中所说的,它对您不起作用,因为您想要设置透视数据。 因此,目前基本上没有办法做到这一点,但像这样的方法应该可以做到:

// belongsToMany.php
public function attachOrUpdate($id, array $attributes = array(), $touch = true)
{
    if ($id instanceof Model) $id = $id->getKey();

    if ( ! $this->allRelatedIds()->contains($id)) // getRelatedIds() in prior to v5.4
    {
        return $this->attach($id, $attributes, $touch); 
    }
    else if ( ! empty($attributes))
    {
        return $this->updateExistingPivot($id, $attributes, $touch);
    }
}

我将对其进行测试,如果通过,则向4.1发送一个pull请求。这看起来像是一个bug,不过您可以这样做:

...->sync([$id], false); // detaching set to false, so it will only insert new rows, skip existing and won't detach anything
编辑: 正如在评论中所说的,它对您不起作用,因为您想要设置透视数据。 因此,目前基本上没有办法做到这一点,但像这样的方法应该可以做到:

// belongsToMany.php
public function attachOrUpdate($id, array $attributes = array(), $touch = true)
{
    if ($id instanceof Model) $id = $id->getKey();

    if ( ! $this->allRelatedIds()->contains($id)) // getRelatedIds() in prior to v5.4
    {
        return $this->attach($id, $attributes, $touch); 
    }
    else if ( ! empty($attributes))
    {
        return $this->updateExistingPivot($id, $attributes, $touch);
    }
}

我将对其进行测试,如果通过,则向4.1发送一个pull请求,您应该使用
updateExistingPivot()

更新您的代码以使用

    $us->updateExistingPivot($lesson->lessonID, 
        ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')], true );
最后一个参数将更新所有相关模型的时间戳。如果没有,可以删除或设置为false

如果只想在记录不存在时附加,可以执行以下操作

Route::post('dbm/users/setLatestSectionID', function() {
    if(Auth::check()) {
        $user = User::find(Input::get('userID'));

        $lesson = [
            "latestSectionID" => Input::get('latestSectionID'), 
            "percentComplete" => Input::get('percentComplete')
        ];

        $num_lessons = $user->lessonStatuses()->where('id', Input::get('lessonID'))->count();

        if($num_lessons == 0) {
            $user->attach($lesson->lessonID, $lesson);
        } else {
            $user->updateExistingPivot($lesson->lessonID, $lesson);

        }
    }
});

您应该使用
updateExistingPivot()

更新您的代码以使用

    $us->updateExistingPivot($lesson->lessonID, 
        ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')], true );
最后一个参数将更新所有相关模型的时间戳。如果没有,可以删除或设置为false

如果只想在记录不存在时附加,可以执行以下操作

Route::post('dbm/users/setLatestSectionID', function() {
    if(Auth::check()) {
        $user = User::find(Input::get('userID'));

        $lesson = [
            "latestSectionID" => Input::get('latestSectionID'), 
            "percentComplete" => Input::get('percentComplete')
        ];

        $num_lessons = $user->lessonStatuses()->where('id', Input::get('lessonID'))->count();

        if($num_lessons == 0) {
            $user->attach($lesson->lessonID, $lesson);
        } else {
            $user->updateExistingPivot($lesson->lessonID, $lesson);

        }
    }
});

我最近遇到了这个问题,并通过以下方式解决了它:

首先使用
updateExistingPivot
并检查结果,如果结果为
1
,则表示存在具有相同
userID
lessonID
的行,并且已成功更新,否则,如果结果为
0
则表示没有具有此
userID
lessonID
的行,因此,您可以附加它以创建新行

    $update_result = $us->updateExistingPivot($lesson->lessonID, 
            ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')] );
    if($update_result == 0) {
        $us->attach($lesson->lessonID, 
            ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')] );
    }

我最近遇到了这个问题,并通过以下方式解决了它:

首先使用
updateExistingPivot
并检查结果,如果结果为
1
,则表示存在具有相同
userID
lessonID
的行,并且已成功更新,否则,如果结果为
0
则表示没有具有此
userID
lessonID
的行,因此,您可以附加它以创建新行

    $update_result = $us->updateExistingPivot($lesson->lessonID, 
            ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')] );
    if($update_result == 0) {
        $us->attach($lesson->lessonID, 
            ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')] );
    }


你的意思是这样的:
$us->sync($lesson->lessonID,[“latestSectionID”=>Input::get('latestSectionID'),“percentComplete”=>Input::get('percentComplete'),false)?出于某种原因,它说参数1是一个字符串而不是数组。它应该是
$us->sync([$lesson->lessonID,[“latestSectionID”=>…
user2..不,sync不接受属性。pg robban我没有注意到您正在更新(或创建)pivot data。更新了我的答案。@decoz手册上说是的,我记得以前没有这个选项。@SarahKemp true,谢谢,编辑过。这就是Laravel的诅咒-以一种没有任何价值的方式更改公共界面,但却给消费者带来了很多破坏BC的问题。你的意思是:
$us->sync($lesson->lessonID,[“latestSectionID”=>Input::get('latestSectionID'),“percentComplete”=>Input::get('percentComplete')),false);
?出于某种原因,它说参数1是字符串而不是数组。它应该是
$us->sync([$lesson->lessonID,[“latestSectionID”)=>…
user2..不,同步不接受属性。pg robban我没有注意到您正在更新(或创建)pivot data。更新了我的答案。@decoz手册上说是的,我记得以前没有这个选项。@SarahKemp true,谢谢,经过编辑。这就是Laravel的诅咒——以一种不会带来任何价值的方式更改公共接口,但却会给消费者带来很多破坏BC的问题。这似乎不会在t中创建行可以。对不起,我想这正是你想要的。你想创建一个,除非已经存在一个,在这种情况下你想更新吗?你理解得没错,但也许我需要澄清:当前的
attach()
方法在行不存在时创建行。但是,在后续调用中,它会创建额外的行,而不是更新现有行。我想你的意思是,我需要先创建关联,然后调用
updateExistingPivot
,对吗?我认为这将是更好的方法,因为一旦你对于
dbm/users/setLatestSectionID
路由,我假设已经为课程创建了一个部分。我更新了答案,但在决定
attach
updateExistingPivot
之前,它会首先检查课程。它会让我
尝试获取
attach行。我认为
where
子句有点奇怪。这将检查
id
列是否等于
lessonID
,但事实并非如此。我已经更新了问题,以澄清表应该是什么样子。这似乎与c无关