【问题标题】:How to add more conditions to a Laravel Relation?如何向 Laravel 关系添加更多条件?
【发布时间】:2014-10-09 16:26:25
【问题描述】:

我有一个具有以下架构的“连接”表:

id 
requestor_id (user_id)
requested_id (user_id)

假设 John Doe(请求者)连接到 Jane Doe(请求),而 Jonnie Doe(请求者)连接到 John Doe(请求)。要列出 John Doe 的所有联系,我必须

inner join "connections" 
  on "users"."id" = "connections"."requested_id" 
  or "users"."id" = "connections"."requestor_id"

但这目前在 Laravel 中是不可能的,因为,afaik,没有 BelongsToMany->or() 方法,那么你会怎么做呢?

【问题讨论】:

    标签: laravel laravel-4 eloquent relationship


    【解决方案1】:

    我设法破解了 Relation 并提出了一个临时解决方案:

    public function connections()
    {
        $relation = $this
            ->belongsToMany(static::class, 'connections', 'requestor_id', 'requested_id')
            ->withTimestamps();
    
        /// delete the already built inner join
        $relation
            ->getQuery() // Eloquent\Builder
            ->getQuery() // Query\Builder
            ->joins = [];
    
        /// create a new inner join with the needed or condition
        $relation->getQuery()->getQuery()->join('connections', function($join)
        {
            $join->on('users.id','=','connections.requestor_id');
            $join->orOn('users.id','=','connections.requested_id');
        });
    
        return $relation;
    }
    

    【讨论】:

      【解决方案2】:

      首先,您需要修复该解决方案,因为它不会返回正确的结果(检查下方)。 其次,它不适用于预加载,所以我不会使用它。

      话虽如此,您可以创建扩展 BelongsToMany 的自定义关系并在模型上调整关系方法,或使用已有的。

      所以让我先提出一些建议,我会找到更好的方法(我将使用朋友而不是关系,以便更容易理解):

      // friendship that I started
      function friendsOfMine()
      {
          return $this->belongsToMany(static::class, 'friends', 'user_id', 'friend_id');
      }
      
      // friendship that I was invited to 
      function friendOf()
      {
          return $this->belongsToMany(static::class, 'friends', 'friend_id', 'user_id');
      }
      
      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->friendOf);
      }
      

      现在它非常易于使用、灵活并且允许预加载:

      $user = User::first();
      
      $user->friends; // merged collection thanks to the accessor
      
      $user->friendOf; // collection of my fans ;)
      
      $user->friendsOfMine; // my idols
      
      $users = User::with('friendOf', 'friendsOfMine')->get();
      

      您的固定解决方案

      问题是,仍然会有where 子句,这会破坏您的查询。因此,您需要将其移动到 joinClause 并在那里再添加一个:

      public function friends()
      {
          $relation = $this
              ->belongsToMany(static::class, 'friends', 'user_id', 'friend_id')
              ->withTimestamps();
      
          // get underlying Query\Builder
          $query = $relation->getQuery()->getQuery();
      
          // get rid of wrong where and its bindings
          $query->setBindings([])
          $query->wheres = [];
      
          // fetch and alter joinClause
          $join = reset($query->joins);
          $join->where('friends.user_id', '=', $this->getKey())
              ->orOn('users.id','=','friends.user_id')
              ->where('friends.friend_id', '=', $this->getKey());
      
      
        // Now the join looks like this:
        //
        // $key = $this->getKey();
        //
        // $query->join('friends', function($join) use ($key)
        // {
        //   $join->on('users.id', '=', 'friends.friend_id')
        //       ->where('friends.user_id', '=', $key)
        //      ->orOn('users.id', '=','friends.user_id')
        //       ->where('friends.friend_id', '=', $key);
        // });
      
          return $relation;   
      }
      

      【讨论】:

        猜你喜欢
        • 2020-02-28
        • 2015-11-25
        • 1970-01-01
        • 2021-08-14
        • 2016-07-13
        • 1970-01-01
        • 1970-01-01
        • 2013-03-15
        • 2018-12-30
        相关资源
        最近更新 更多