首页 文章

使用雄辩的关系

提问于
浏览
1

我试图了解如何有效地使用Eloquent关系在模型中具有一些高级功能 . 我有一个包含2个表,“用户”和“订阅”的订阅应用程序 . 这是一个遗留系统,所以我不能以任何我想要的方式改变事物 .

Table users (model App\User)
 id
 email
 active (0/1)
 join_date
 address etc
 phone

 Table subscriptions (model App\Subscription)
 id
 user_id
 box_id (what the person is subscribed to get)
 amount

用户被标记为活动或未激活 .

我想在Subscription模型上有一个静态方法,它将为我提供所有活动订阅 . 然后将该数据输入应用程序的其他部分 .

这是通过将订阅加入用户并基于 active 列进行过滤得出的 . 查询是这样的:

SELECT users.*, subscriptions.*
FROM subscriptions
JOIN users ON users.id = subscriptions.user_id
WHERE users.active = 1

订阅模型

class Subscription extends Model
{
    public static function allActive()
    {
        // This works except it doesn't use the eloquent relationship
        return static::where('users.active', 1)
            ->join('users', 'users.id', '=', 'subscriptions.user_id')
            ->select('users.*','subscriptions.*')
            ->get();
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

用户模型

class User extends Authenticatable
{
    use Notifiable;
    public function subscriptions()
    {
        return $this->hasMany(Subscription::class);
    }
}

我会像这样使用它:

$subscriptions = \App\Subscription::allActive()->toArray();
print_r($subscriptions);

我有两个问题 .

  • 如何重写 allActive 函数以使用我已定义的关系?任何解决方案都应该使用JOIN生成SQL .

  • 在返回的数据中,如何将列与两个单独的表分开,以便清楚数据来自哪个表?

1 回答

  • 0

    鉴于您已连接的关系,要从模型类中仅获取活动订阅,您必须这样做:

    class Subscription extends Model
    {
        public static function allActive()
        {
            $activeSubcriptions = Subscription::whereHas('user', function($query){
                $query->where('active', 1) //or you could use true in place of 1
            })->get();
            return $activeSubcriptions;
        }
    
        public function user()
        {
            return $this->belongsTo(User::class);
        }
    }
    

    那就是在Laravel中使用 closures ,这是编写高级雄辩查询的一种有效方式 .

    在回调函数中,你将使用$ query 对象做很多事情,它基本上处理用户模型,因为你提到它是 ->whereHas 的第一个参数

    请注意,该变量必须具有与声明关系时使用的 EXACTLY 相同的名称

    以上我想回答你的第一个问题,但强烈建议你在控制器文件中完成大部分逻辑

    要回答问题2,当您执行 get() 时,它将返回 Subscription 对象数组,以便根据您必须使用的列访问信息:

    $subscriptions = \App\Subscription::allActive();
    
    foreach($subscriptions as $subscription){
        $amount = $subscription->amount; //this you access directly since we working with the subscription object
        $box_id = $subscription->box_id;
    
        //when accessing user columns
        $email = $subscription->user->email; //you will have to access it via the relationship you created
        $address = $subscription->user->address;
    }
    

相关问题