Php 如何迫使Laravel Elount很好地处理一个不返回结果的查询?

Php 如何迫使Laravel Elount很好地处理一个不返回结果的查询?,php,mysql,exception,laravel,eloquent,Php,Mysql,Exception,Laravel,Eloquent,在我的一个模型中,我将一个数据库查询设置为作用域查询,在某些情况下可能不会返回任何结果,这样做完全可以: public function scopeLastFromLaunchSite($query, $site) { return $query->whereComplete()->whereHas('launchSite', function($q) use($site) { $q->where('name',$site); })->or

在我的一个模型中,我将一个数据库查询设置为作用域查询,在某些情况下可能不会返回任何结果,这样做完全可以:

public function scopeLastFromLaunchSite($query, $site) {
    return $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
        $q->where('name',$site);
    })->orderBy('launch_order_id','DESC')->first();
}
此函数仅通过以下方式调用:

Mission::LastFromLaunchSite('someSite');
如果结果中至少有一行,则此查询工作得非常好,但一旦没有一行,它就会返回一个非常长的生成器对象,其中充满了递归,这实际上会使我的浏览器崩溃

我的问题是。。。 我如何检测到这一点并简单地返回类似于
false
的内容“未找到任何结果”。

我试过的。。。 我尝试使用
firstOrFail()
方法代替
first()
,但这只会返回一个
ModelNotFoundException
,它提供了两种解决方案:

  • 使用
    App:error
    global.php
    中处理它。这是不可取的,因为没有返回的结果不是错误。这只是众多可能结果之一

  • 捕获每个方法中的异常,这将导致代码重复。事实上,我也没能让它起作用。我尝试
    使用
    ModelNotFoundException
    类并捕获它,但它从未被捕获:

    use Illuminate\Database\Eloquent\ModelNotFoundException;
    
    // ...
    
    try {
        //my query
    } catch (Illuminate\Database\Eloquent\ModelNotFoundException $e) {
        return false;
    }
    
    // otherwise, return as normal
    

  • 当对我的模型的查询没有返回结果时,我怎么能简单地返回
    false
    或某个假值,而不是简单地打印出这个非常长的错误?

    我从来没有做过这样的事情,但我首先想到的是这样的事情:

    public function scopeLastFromLaunchSite($query, $site) {
        $retVal = $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
            $q->where('name', $site);
        })->orderBy('launch_order_id', 'DESC');
    
        if ($retVal->count() > 0) {
            return $retVal->first();
        }
    
        return "No results found";
    }
    

    这里的问题是,您没有像Laravel那样使用作用域。Laravel实际上并不期望您在范围内执行查询。它是一个应用过滤器的工具。因此,当作用域函数返回
    NULL
    (或任何falsy值)时,Laravel将只返回当前的生成器对象:

    illumb\Database\elount\Builder

    protected function callScope($scope, $parameters)
    {
        array_unshift($parameters, $this);
    
        return call_user_func_array(array($this->model, $scope), $parameters) ?: $this;
    }
    
    以下是三种解决方案:

    1.使用异常(但在控制器中) 我不太喜欢这个,但这是可能的。使用
    first或fail
    并在控制器中执行此操作:

    try {
        $result = Mission::LastFromLaunchSite('someSite');
    } catch (Illuminate\Database\Eloquent\ModelNotFoundException $e){
        $result = null;
    }
    
    public function scopeLastFromLaunchSite($query, $site) {
        return $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
            $q->where('name',$site);
        })->orderBy('launch_order_id','DESC');
    }
    
    2.正确使用范围 不要在作用域中执行查询,而是在控制器中执行查询:

    try {
        $result = Mission::LastFromLaunchSite('someSite');
    } catch (Illuminate\Database\Eloquent\ModelNotFoundException $e){
        $result = null;
    }
    
    public function scopeLastFromLaunchSite($query, $site) {
        return $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
            $q->where('name',$site);
        })->orderBy('launch_order_id','DESC');
    }
    
    用法:

    Mission::LastFromLaunchSite('someSite')->first();
    
    Mission::LastFromLaunchSite('someSite');
    
    3.只需在模型中添加一个普通函数即可 用法:

    Mission::LastFromLaunchSite('someSite')->first();
    
    Mission::LastFromLaunchSite('someSite');
    

    作用域不应该返回查询结果,这就是为什么根据您的代码,您会得到永无止境的递归或其他错误

    将范围更改为:

    public function scopeLastFromLaunchSite($query, $site) {
        $query->whereComplete()->whereHas('launchSite', function($q) use($site) {
            $q->where('name',$site);
        })->orderBy('launch_order_id','DESC');
    }
    
    然后就地执行:

    $result = $yourQuery->lastFromLaunchSite($site)->first();
    
    // then do whatever you need with the result
    return ($result) ?: 'nothing found!';
    

    说明:作用域不需要返回值。如果scopewhater
    方法返回的值为
    true`,则它将替换基本查询,否则将返回查询本身。也就是说,如果您希望返回单个模型,但没有行匹配条件,那么您会意外地得到查询对象

    您可以这样做(我不会,但也可以):


    但是,您需要体验
    模型
    字符串
    ,并相应地调整代码,以避免可能的
    尝试获取非对象属性
    错误。

    如何调用此函数?添加到问题中。您无需调用查询两次。只需检查结果的计算结果是否为
    true