【问题标题】:Proper way of handling scopes with pivot involved处理涉及枢轴的范围的正确方法
【发布时间】:2017-02-01 00:27:25
【问题描述】:

作为一个使用 laravel 几个月的用户,我正在努力更好地了解 Eloquent 的高级用法。

我遇到了一个案例,我无法想出一个感觉正确的解决方案。

我有以下结构(简化)

Mandate
id
status_id

Mandate_user
mandat_id
user_id
link_status

User
id

我通过数据透视表在 User 和 Mandat 中声明了 belongsToMany。

关于用户:

 public function mandates(){
        return belongsToMany(..)->withPivot('link_status');
    }

我可以通过使用为用户获得接受的授权

public function acceptedMandates(){
     return $this->mandates()->wherePivot('link_status', MandateUserStatus::Accepted);
}

这可行,但我想知道是否有更好的方法通过使用范围或其他雄辩的方法。 而且我正在尝试接受 status_id 低于 4 的任务(也来自枚举)

我想到了类似的东西:

public function runningMandates(){
     return $this->acceptedMandates()->where('status_id','<', 4);
}

然后像这样收集任务:

$mandates = User::find(1)->runningMandates();

但是,雄辩的方式会是这样的:

$mandates = User::find(1)->mandates()->running()->accepted();

感谢您的宝贵时间。

【问题讨论】:

    标签: database laravel laravel-5 eloquent laravel-5.2


    【解决方案1】:

    这是一个非常主观的问题,很难给出直接的答案,但希望我能阻止你对自己的猜测:你正在做的事情非常好,并且不亚于其他人的“雄辩”。

    就我个人而言,我更喜欢你现在所做的事情,而不是你呈现为“雄辩的方式”的方式,并且以前在专业项目中也这样做过,但最终你为框架或代码设计代码的方式有所不同包,它必须灵活以适应许多不同的场景,其中大多数场景是你在做第一版时甚至无法想象的,而不是你如何为一个只会被自己使用的应用程序设计代码。如果您知道驱动您的应用程序的业务逻辑以及它将呈现给用户的视图(随后,它必须执行的查询),那么您为什么不创建可以轻松实现这一目标的方法呢?

    Eloquent 依赖链接不仅因为它很酷,还因为它不知道(或不关心)您的业务逻辑是什么。对我来说,“Eloquent way”更多的是关于流畅、可读的代码,我发现$user-&gt;runningMandates$user-&gt;mandates()-&gt;running()-&gt;accepted()-&gt;get()更具可读性。

    我还发现第一种方法更容易进入。如果您不断强迫自己分离方法以便将它们链接起来,则可能更难掌握哪种方法在做什么以及哪种方法依赖于哪个方法。查询范围可以根据需要修改查询(连接、别名等),因此危险在于一种方法需要另一种方法首先出现,因为您基于不在原始查询中的表或列进行调节,所以一种方法只能与另一种方法结合使用;或者可能有两种方法试图加入同一个表,或者使用相同的别名,所以它们不能一起使用。这可能看起来有些牵强,但通常将事物分开和整洁的努力会使您的代码更难使用。但是,即使事情没有在代码方面发生问题,对我来说,交易破坏者也会忽略业务逻辑:在您的情况下,为runningaccepted 设置两个单独的范围是否有意义?如果不被接受,授权可以是running吗?如果没有,您应该尝试防止知识较少的开发人员创建有缺陷的查询(逻辑方面)。正如您所说,结构已简化,因此可能存在其他问题,而且随着应用程序复杂性的增加,还会出现更多问题。

    如果我要接管别人的代码,我宁愿使用有限的、自包含的方法,这些方法不会破坏简单、分散的方法,这些方法需要您阅读(通常不存在)文档以防止滥用它们的多种方式。

    【讨论】:

    • 谢谢!我也更喜欢我的方法,但随着应用程序越来越大而我的用户模型越来越长,我问自己。我可能会根据上下文进行调整和使用。
    【解决方案2】:

    基本上,scopes 为查询添加约束,因此您可以使用scope 方法通过调用范围方法来修改查询,最终让您有机会动态进行查询。因此,您可以声明(就像您所做的那样)一个关系方法,您可以在其中执行所有查询并调用该特定方法或使用范围方法两个使用方法调用构建查询,其中每个方法都添加一个约束。在这种情况下,它会更加动态,但它仍然是一种偏好,它给你更多的灵活性(IMO)。所以是的,您可以为此使用查询范围,例如:

    // Declare the main relationship
    public function mandates()
    {
        return $this->belongsToMany(..)->withPivot('link_status');
    }
    

    现在,为accepted 声明查询范围(对mandates 方法调用返回的查询添加一个约束)

    public function scopeAccepted($query)
    {
        return $query->wherePivot('link_status', MandateUserStatus::Accepted);
    }
    

    现在,为running 添加另一个查询范围,例如:

    public function scopeRunning($query)
    {
        return $query->where('status_id','<', 4);
    }
    

    现在,如果你调用如下代码:

    $user = User::find(1);
    

    现在,调用关系方法(不是作为属性)

    $mendates = $user
    ->mandates() // The method is called and a query object is constructed
    ->running() // Add another constraint into the query: ->where('status_id','<', 4)
    ->accepted() // Add another constraint into the query: ...
    ->get(); // Finally, execute the query to get the result
    

    也许,你现在很清楚了。注意方法调用mandates(),它是对定义的关系的方法调用,它返回Query Builder,并且通过链接其他范围方法调用,您只是通过添加更多约束来修改查询,但您可以在一个中完成所有查询没有动态范围的方法,所以这取决于你。虽然,范围为您提​​供了更大的灵活性,但这并不意味着您必须始终遵循这种方法,这取决于。

    【讨论】:

    • 感谢您的示例。不过,正如@Thomas 在他的回答中指出的那样,一个问题是,接受的范围将取决于先前对命令()的调用,对吗?否则枢轴为空
    猜你喜欢
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 2016-01-31
    • 2019-12-10
    • 2020-11-16
    • 2018-08-26
    • 2016-02-19
    相关资源
    最近更新 更多