Метод Laravel belongsToMany attach() не работает после использования метода contains в том же отношении

#laravel #many-to-many

#laravel #многие ко многим

Вопрос:

Я работаю над реализацией дружбы в своем проекте, но в дополнение к добавлению друзей я хотел бы иметь функцию приглашения, как в Facebook, я использую подход «многие ко многим», ссылающийся на себя,

схема сводной таблицы:

     Schema::create('user_friends', function (Blueprint $table) {
        $table->primary(['user_id', 'friend_id']);
        $table->unsignedInteger('user_id');
        $table->unsignedInteger('friend_id');
        $table->timestamps();
        $table->timestamp('accepted_at')->nullable()->default(null);
        $table->timestamp('refused_at')->nullable()->default(null);

        $table->foreign('user_id')
        ->references('id')->on('users')
        ->onDelete('cascade');
        $table->foreign('friend_id')
        ->references('id')->on('users')
        ->onDelete('cascade');
    });
  

Я делю друзей / будущих друзей на 3 группы:

  1. Подтвержденные друзья, и в эту категорию входят друзья, которых я приглашаю, и друзья, которые приглашают меня;
  2. Приглашенные: те, кого я приглашаю, но не одобрил;
  3. Приглашающие: те, кто приглашает меня, но я еще не говорю «да».

Ниже приведен их соответствующий код:

Группа 1: друзья:

     class User {

    //

    /**
     * Friendships that started by the user
     */
    public function friendsOfMine()
    {
        return $this->belongsToMany('AppUser', 'user_friends', 'user_id', 'friend_id')
                    ->withPivot(['accepted_at', 'refused_at'])
                    ->wherePivot('accepted_at', '<>', null)
                    ->withTimestamps();
    }

    /**
     * Friendships that started by others
     */
    public function friendOfOthers()
    {
        return $this->belongsToMany('AppUser', 'user_friends', 'friend_id', 'user_id')
                    ->withPivot(['accepted_at', 'refused_at'])
                    ->wherePivot('accepted_at', '<>', null)
                    ->withTimestamps();
    }

    // accessor allowing you call $user->friends
    public function getFriendsAttribute()
    {
        if (!array_key_exists('friends', $this->relations)) {
            $this->loadFriends();
        }

        return $this->getRelation('friends');
    }

    protected function loadFriends()
    {
        if (!array_key_exists('friends', $this->relations)) {
            $friends = $this->mergeFriends();

            $this->setRelation('friends', $friends);
        }
    }

    protected function mergeFriends()
    {
        return $this->friendsOfMine->merge($this->friendOfOthers);
    }
  

Группа 2: Приглашенные:

 /**
 * Users that are invited as friends by this user.
 */
public function invitees()
{
    return $this->belongsToMany('AppUser', 'user_friends', 'user_id', 'friend_id')
                ->withPivot(['accepted_at', 'refused_at'])
                ->wherePivot('accepted_at', null)
                ->withTimestamps();
}
  

Группа 3: инвайтеры:

 /**
 * Users that invite this user as friend.
 */
public function invitors()
{
    return $this->belongsToMany('AppUser', 'user_friends', 'friend_id', 'user_id')
                ->withPivot(['accepted_at', 'refused_at'])
                ->wherePivot('accepted_at', null)
                ->withTimestamps();
}
  

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

 public function inviteFriend(User $user)
{

    if (!$this->is($user) amp;amp;
        !$this->friends->contains($user) amp;amp;
        !$this->invitees->contains($user) amp;amp;
        !$this->invitors->contains($user)) {

        $this->invitees()->attach($user);  
    }
}
  

Затем возникает странная проблема, я использовал dd() для проверки хода выполнения и подтверждения того, что условие выполнено и

 $this->invitees()->attach($user);
  

был выполнен, но, однако, $user не был добавлен правильно,
но если я удалю эту самую проверку одного условия (а не другого)

 !$this->invitees->contains($user)
  

и функция становится

 public function inviteFriend(User $user)
{

    if (!$this->is($user) amp;amp;
        !$this->friends->contains($user) amp;amp;
        // !$this->invitees->contains($user) amp;amp;
        !$this->invitors->contains($user)) {

        $this->invitees()->attach($user);  
    }
}
  

Тогда это будет работать нормально, но, тем не менее, тогда можно будет повторно приглашать одного и того же человека, а затем вызывать нарушение ограничений SQL.

Кто-нибудь может мне помочь в этом? Заранее благодарю вас!!!

Ответ №1:

Вы можете использовать syncWithoutDetaching вместо функции attach :

 public function inviteFriend(User $user)
{

  if (!$this->is($user) amp;amp;
    !$this->friends->contains($user) amp;amp;
    !$this->invitors->contains($user)) {

    $this->invitees()->syncWithoutDetaching([$user->id]);  
  }
}
  

эта функция прикрепляет идентификатор пользователя, если он не существует

Комментарии:

1. Спасибо за ваш ответ, я попробовал ваше предложение, но оно дает тот же результат, что и мой исходный код.

Ответ №2:

После дополнительных поисков я, наконец, нашел обходной путь для решения моей проблемы, и я думаю, что этот подход может быть лучше, чем мой первоначальный, с точки зрения эффективности, поскольку collection->contains() кажется излишним для такого рода ситуаций.

     if (!$this->is($user) amp;amp;
        !$this->friendsOfMine()->wherePivot('friend_id', $user->id)->exists() amp;amp;
        !$this->friendOfOthers()->wherePivot('user_id', $user->id)->exists() amp;amp;
        !$this->invitees()->wherePivot('friend_id', $user->id)->exists() amp;amp;
        !$this->invitors()->wherePivot('user_id', $user->id)->exists()) {
        $this->invitees()->attach($user);
   }