【问题标题】:Eloquent Query Scope on Relationships关系上的雄辩查询范围
【发布时间】:2016-04-09 02:30:47
【问题描述】:

我有两个模型,App\Song(属于 App\Host)和 App\Host(hasMany App\Song)。

我的控制器中有以下查询:

$songs = Song::whereHas('host', function($query) {
                $query->where('skip_threshold', '>', \DB::raw('songs.attempts'))
                      ->where('active', 1);
            })
->whereNull('downloaded')
->get();

为了可重用性,我想变成一个查询范围。

我对 Eloquent 很陌生,所以我不确定这是不是正确的方法,因为它的两个模型没有返回任何结果(应该有)。

Song.php

public function scopeEligable($query)
{
    $query->where('skip_threshold', '>', \DB::raw('songs.attempts'));
}

public function scopeActiveHost($query)
{
    $query->where('active', 1);
}

public function scopeInDownloadQueue($query)
{
    $query->whereNull('downloaded');
}

【问题讨论】:

  • 控制器中用于调用这些查询范围的代码是什么? (不返回结果?)
  • Song::eligable()->activehost()->indownloadqueue()->get();
  • 您应该在所有范围内都有return..return $query->whereNull('downloaded');。范围应始终返回一个查询构建器实例。 laravel.com/docs/5.1/eloquent#query-scopes
  • 我已更新范围以返回查询,但仍未返回任何数据
  • 你可能需要直接看一下sql。你有 DebugBar 安装吗?如果在您的查询调用之前不尝试这个... \Event::listen('illuminate.query', function($query, $params, $time, $conn) { dd(array($query, $params, $time , $conn)); });

标签: php laravel eloquent


【解决方案1】:

您应该将作用域放入它们所属的模型中。查看您的初始查询范围 scopeEligablescopeActiveHost 属于 Host 模型,因此您应该将它们移动到 Host 模型中,然后您将能够使用以下范围使用您的查询:

$songs = Song::whereHas('host', function($query) {
   $query->eligable()->activeHost();
})->inDownloadedQueue()->get();

正如评论中已经指出的那样,您应该将return 添加到每个范围,以便可以按预期使用它们。

编辑

如果您想缩短使用时间,可以在Song 模型中创建新关系:

public function activeHost() 
{
    return $this->belongsTo(Host:class)->eligable()->activeHost();
}

所以现在,你可以写:

$songs = Song::whereHas('activeHost')->inDownloadedQueue()->get();

【讨论】:

  • 这按预期工作,但这仍然需要三行代码,为了简单起见,代码中有没有办法可以将其缩短为单行?
  • 嗨,Marcin,我现在正在使用该代码,但它似乎没有按预期工作。我尝试使用->toSql() 函数进行调试并生成以下SQL:select * from "songs" where exists (select * from "hosts" where "songs"."host_id" = "hosts"."id" and "skip_threshold" > songs.attempts and "active" = ?) and "downloaded" is null。有什么想法吗?
【解决方案2】:

我认为您对 2 个模型有误。我认为这应该可行

Song.php

public function scopeEligable($query, $active) {
   return $query->whereHas('host', function($q) {
       $q->where('skip_threshold', '>', \DB::raw('songs.attempts'))->where('active', $active);
   })
}

public function scopeInDownloadQueue($query)
{
   $query->whereNull('downloaded');
}

用法

$songs = Song::eligable(true)->inDownloadQueue()->get();

【讨论】:

    猜你喜欢
    • 2021-06-17
    • 2016-07-01
    • 2016-02-26
    • 2018-12-09
    • 2015-03-26
    • 2014-01-16
    • 2018-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多