使用枢轴处理范围的正确方法

时间:2016-09-23 08:06:38

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

作为一个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();

感谢您的时间。

2 个答案:

答案 0 :(得分:3)

这是一个非常主观的问题,很难直截了当地回答,但希望我可以阻止你自己进行二次猜测:你所做的事情是完美无缺的,而且并不是那么有说服力。样&#34;比另一个。

就我个人而言,我现在更喜欢你所做的事情,而不是你所表现出来的那种“雄辩的方式”#34;并且在专业项目之前已经这样做了,但最终在为框架或包设计代码的方式上存在差异,这对于许多不同的场景必须是灵活的,大多数情况在执行第一版时甚至无法想象,而不是你如何设计一个只能自己消费的应用程序的代码。如果你知道驱动你的应用程序的业务逻辑以及它将呈现给用户的视图(随后,它必须执行的查询),为什么你不能创建容易实现的方法是什么?

Eloquent依赖链接不仅仅因为它很酷,而且因为它不知道(或不知道)你的业务逻辑是什么。对我来说,&#34;雄辩的方式&#34;更多是关于流畅,可读的代码,我发现$user->runningMandates$user->mandates()->running()->accepted()->get()更具可读性。

我还发现第一种方法更容易进入。如果您经常强迫自己分离方法以便将它们链接起来,那么可能更难理解哪种方法正在做什么以及哪种方法依赖于哪种方法。查询范围可以根据需要修改查询(连接,别名等),因此危险在于一种方法需要另一种方法,因为您需要根据不在其上的表或列进行调整。原始查询,所以一个方法只能与另一个方法一起工作;或者可能有两种方法试图加入同一个表,或使用相同的别名,因此它们不能一起使用。这可能看起来很牵强,但通常保持分离和整洁的努力会使您的代码更难使用。但是,即使事情不会在代码方面爆炸,对我而言,交易中断会忽略业务逻辑:在你的情况下,为running和{{1}设置两个独立的范围是否有意义}}?如果不被接受,授权可以accepted吗?如果没有,您应该尝试阻止知识渊博的开发人员创建有缺陷的查询(逻辑方面)。正如你所说,结构已经简化,因此可能还有其他陷阱,随着应用程序的复杂性增加,还会有更多的问题。

如果我接管其他人的代码,我宁愿采用有限的,自包含的方法,而不是打破需要你阅读的简单,分散的方法(通常不存在的文档,以防止误用它们的方法很多。

答案 1 :(得分: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并通过链接其他范围方法调用,你只是通过添加一些更多的约束来修改查询但是你可以在没有动态范围的情况下在一个方法中执行所有查询,因此它取决于您。虽然范围为您提​​供了更大的灵活性,但它并不意味着您始终遵循这种方法,这取决于。