【问题标题】:Using eloquent relation使用雄辩的关系
【发布时间】:2019-05-10 06:36:29
【问题描述】:

我正在尝试了解如何有效地使用 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

用户被标记为活跃或不活跃。

我想在订阅模型上有一个静态方法,它会给我所有的活动订阅。然后将这些数据馈送到应用程序的其他部分。

这是通过将订阅加入用户并基于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);

我有 2 个问题。

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

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

【问题讨论】:

标签: php laravel-5 eloquent


【解决方案1】:

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

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,这是编写高级 eloquent 查询的一种非常有效的方式。

在回调函数中,您几乎可以对 $query 对象执行任何操作,它基本上适用于 User 模型,因为您提到它是 ->whereHas 的第一个参数

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

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

要回答问题 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;
}

【讨论】:

  • 谢谢。 Subscription->whereHas 看起来不对。你的意思是$this->whereHas
  • 我对此做了一些测试。此解决方案有效,但它为每个用户生成单独的查询,而不是使用连接执行一个查询。
  • 这一切都取决于您打算做什么,但我很确定您的主要问题已得到解答。干杯
  • 原题中有查询。此解决方案不会生成该查询。相反,它会为每个用户创建许多单独的查询。这是低效且不可扩展的。当我有 10000 个订阅者时会发生什么?据我所知,没有办法按照我的要求去做。即使用关系生成连接查询。
猜你喜欢
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 2017-01-16
  • 2014-08-27
相关资源
最近更新 更多